zjk
5 小时以前 8ea6a7dd1fcdbd4e22c564ed63a5a8023510161a
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'
    }
}