|
|
@@ -1,11 +1,35 @@
|
|
|
<!--
|
|
|
- 商城「我的」资料编辑:改昵称、看/改生日、退出登录。
|
|
|
+ 商城「我的」资料编辑:改头像、改昵称、看/改生日、退出登录。
|
|
|
+ 头像走 /upload/save-file?actType=saveAvatar,后端会写 user 与客户表;成功后同步 vuex loginInfo。
|
|
|
改昵称成功后必须写入 vuex loginInfo,否则返回「我的」仍显示旧名字。
|
|
|
-->
|
|
|
<template>
|
|
|
<div class="app-content">
|
|
|
<form @submit="formSubmit">
|
|
|
<div class="module-com input-line-wrap">
|
|
|
+ <!-- 头像:微信用 chooseAvatar;其它端选相册/相机后上传 -->
|
|
|
+ <tui-list-cell class="line-cell avatar-cell" :hover="false">
|
|
|
+ <div class="tui-title">头像</div>
|
|
|
+ <div class="avatar-wrap">
|
|
|
+ <!-- #ifdef MP-WEIXIN -->
|
|
|
+ <button
|
|
|
+ class="avatar-btn"
|
|
|
+ open-type="chooseAvatar"
|
|
|
+ :disabled="uploadingAvatar"
|
|
|
+ @chooseavatar="onChooseAvatar"
|
|
|
+ >
|
|
|
+ <image class="avatar-img" :src="avatarDisplay" mode="aspectFill" />
|
|
|
+ <text class="avatar-tip">更换</text>
|
|
|
+ </button>
|
|
|
+ <!-- #endif -->
|
|
|
+ <!-- #ifndef MP-WEIXIN -->
|
|
|
+ <div class="avatar-btn" @click="chooseLocalAvatar">
|
|
|
+ <image class="avatar-img" :src="avatarDisplay" mode="aspectFill" />
|
|
|
+ <text class="avatar-tip">更换</text>
|
|
|
+ </div>
|
|
|
+ <!-- #endif -->
|
|
|
+ </div>
|
|
|
+ </tui-list-cell>
|
|
|
<tui-list-cell class="line-cell" :hover="false">
|
|
|
<div class="tui-title">昵称</div>
|
|
|
<input v-model="form.name" placeholder-class="phcolor" class="tui-input" name="name" placeholder="请填写" type="nickname" />
|
|
|
@@ -34,6 +58,8 @@
|
|
|
</template>
|
|
|
<script>
|
|
|
import TuiListCell from '@/components/plugin/list-cell'
|
|
|
+import constant from '@/constant/index'
|
|
|
+import { TOKEN_STORAGE_KEY } from '@/constant/storageKeys'
|
|
|
const form = require('@/utils/formValidation.js')
|
|
|
import { currentInfo,updateInfo,clearLogin } from "@/api/user";
|
|
|
export default {
|
|
|
@@ -46,7 +72,31 @@ export default {
|
|
|
form: {
|
|
|
name: ''
|
|
|
},
|
|
|
- userInfo:{}
|
|
|
+ userInfo:{},
|
|
|
+ /** 头像上传中,防止重复点选 */
|
|
|
+ uploadingAvatar: false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ /**
|
|
|
+ * 展示用头像:优先 smallAvatar,无则用大图,再回落默认图
|
|
|
+ */
|
|
|
+ avatarDisplay() {
|
|
|
+ const info = this.userInfo || {}
|
|
|
+ if (info.smallAvatar) {
|
|
|
+ return info.smallAvatar
|
|
|
+ }
|
|
|
+ if (info.avatar) {
|
|
|
+ return info.avatar
|
|
|
+ }
|
|
|
+ const login = this.$store.getters.getLoginInfo || {}
|
|
|
+ if (login.smallAvatar) {
|
|
|
+ return login.smallAvatar
|
|
|
+ }
|
|
|
+ if (login.avatar) {
|
|
|
+ return login.avatar
|
|
|
+ }
|
|
|
+ return `${this.constant.imgUrl}/retail/default-img.png`
|
|
|
}
|
|
|
},
|
|
|
onLoad() {
|
|
|
@@ -82,7 +132,7 @@ export default {
|
|
|
//this.getLoginInfo();
|
|
|
},
|
|
|
/**
|
|
|
- * 拉取当前登录用户信息:回填生日展示,并把已有昵称写入 form.name 供输入框渲染
|
|
|
+ * 拉取当前登录用户信息:回填生日/头像展示,并把已有昵称写入 form.name 供输入框渲染
|
|
|
*/
|
|
|
getLoginInfo(){
|
|
|
currentInfo().then(res=>{
|
|
|
@@ -97,6 +147,97 @@ export default {
|
|
|
goToBirthday() {
|
|
|
this.pageTo({ url: '/pages/user/birthday'})
|
|
|
},
|
|
|
+ /**
|
|
|
+ * 微信头像能力回调:拿到临时路径后上传并落库
|
|
|
+ * @param {Object} e chooseavatar 事件,e.detail.avatarUrl 为临时文件路径
|
|
|
+ */
|
|
|
+ onChooseAvatar(e) {
|
|
|
+ const filePath = e && e.detail && e.detail.avatarUrl
|
|
|
+ if (!filePath) {
|
|
|
+ this.$msg('未获取到头像')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.uploadAvatar(filePath)
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 非微信端:从相册/相机选图后上传为头像
|
|
|
+ */
|
|
|
+ chooseLocalAvatar() {
|
|
|
+ if (this.uploadingAvatar) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ uni.chooseImage({
|
|
|
+ count: 1,
|
|
|
+ sizeType: ['compressed'],
|
|
|
+ sourceType: ['album', 'camera'],
|
|
|
+ success: (res) => {
|
|
|
+ const paths = res.tempFilePaths || []
|
|
|
+ if (!paths.length) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.uploadAvatar(paths[0])
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 上传头像到 /upload/save-file?actType=saveAvatar。
|
|
|
+ * 后端会更新 user.avatar 与客户表 avatar;前端用返回的 url/smallUrl 刷新本页与 loginInfo。
|
|
|
+ * @param {String} filePath 本地临时图片路径
|
|
|
+ */
|
|
|
+ uploadAvatar(filePath) {
|
|
|
+ if (!filePath || this.uploadingAvatar) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.uploadingAvatar = true
|
|
|
+ uni.showLoading({ title: '上传中', mask: true })
|
|
|
+ const token = uni.getStorageSync(TOKEN_STORAGE_KEY) || uni.getStorageSync('token') || ''
|
|
|
+ const account = uni.getStorageSync('account') || ''
|
|
|
+ const header = { token }
|
|
|
+ if (account) {
|
|
|
+ header.account = account
|
|
|
+ }
|
|
|
+ uni.uploadFile({
|
|
|
+ url: constant.hostUrl + '/upload/save-file?actType=saveAvatar',
|
|
|
+ filePath,
|
|
|
+ name: 'file',
|
|
|
+ header,
|
|
|
+ success: (uploadRes) => {
|
|
|
+ try {
|
|
|
+ const body = typeof uploadRes.data === 'string'
|
|
|
+ ? JSON.parse(uploadRes.data)
|
|
|
+ : uploadRes.data
|
|
|
+ if (body && body.code == 1 && body.data) {
|
|
|
+ const avatar = body.data.url || body.data.bigUrl || ''
|
|
|
+ const smallAvatar = body.data.smallUrl || avatar
|
|
|
+ // 本页立即换图,避免再拉一次接口
|
|
|
+ this.userInfo = Object.assign({}, this.userInfo, {
|
|
|
+ avatar,
|
|
|
+ smallAvatar,
|
|
|
+ shortAvatar: body.data.shortUrl || this.userInfo.shortAvatar
|
|
|
+ })
|
|
|
+ // 「我的」页读 loginInfo.avatar,必须同步 vuex
|
|
|
+ const loginInfo = Object.assign({}, this.$store.getters.getLoginInfo || {}, {
|
|
|
+ avatar,
|
|
|
+ smallAvatar
|
|
|
+ })
|
|
|
+ this.$store.commit('setLoginInfo', loginInfo)
|
|
|
+ this.$msg('头像已更新')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.$msg((body && body.msg) || '上传失败')
|
|
|
+ } catch (err) {
|
|
|
+ this.$msg('上传失败')
|
|
|
+ }
|
|
|
+ },
|
|
|
+ fail: () => {
|
|
|
+ this.$msg('上传失败')
|
|
|
+ },
|
|
|
+ complete: () => {
|
|
|
+ this.uploadingAvatar = false
|
|
|
+ uni.hideLoading()
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
/**
|
|
|
* 提交昵称:校验后调 /user/update,并把新名字写入 loginInfo(含本地缓存)。
|
|
|
* 「我的」页读的是 loginInfo.name,只改接口不写 vuex 会看起来没更新。
|
|
|
@@ -138,24 +279,67 @@ export default {
|
|
|
color: $fontColor2;
|
|
|
line-height: 80upx;
|
|
|
}
|
|
|
+ /* 昵称内容靠右,与头像/生日行一致 */
|
|
|
.tui-input {
|
|
|
+ flex: 1;
|
|
|
width: calc(100% - 210upx);
|
|
|
font-size: 28upx;
|
|
|
min-height: 80upx;
|
|
|
padding: 20upx;
|
|
|
+ text-align: right;
|
|
|
}
|
|
|
.tui-placeholder {
|
|
|
color: #ccc;
|
|
|
}
|
|
|
.phcolor {
|
|
|
color: #ccc;
|
|
|
+ text-align: right;
|
|
|
}
|
|
|
+ /* 生日文案、去设置靠右 */
|
|
|
.birthday-display {
|
|
|
+ flex: 1;
|
|
|
min-height: 80upx;
|
|
|
padding: 20upx;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
+ justify-content: flex-end;
|
|
|
font-size: 28upx;
|
|
|
+ text-align: right;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /* 头像行:右侧预览 + 更换入口,与昵称行对齐 */
|
|
|
+ .avatar-cell {
|
|
|
+ .avatar-wrap {
|
|
|
+ flex: 1;
|
|
|
+ display: flex;
|
|
|
+ justify-content: flex-end;
|
|
|
+ align-items: center;
|
|
|
+ min-height: 80upx;
|
|
|
+ padding: 10upx 20upx;
|
|
|
+ }
|
|
|
+ .avatar-btn {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: flex-end;
|
|
|
+ margin: 0;
|
|
|
+ padding: 0;
|
|
|
+ background: transparent;
|
|
|
+ border: none;
|
|
|
+ line-height: 1;
|
|
|
+ &::after {
|
|
|
+ border: none;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .avatar-img {
|
|
|
+ width: 96upx;
|
|
|
+ height: 96upx;
|
|
|
+ border-radius: 50%;
|
|
|
+ background: #f5f5f5;
|
|
|
+ }
|
|
|
+ .avatar-tip {
|
|
|
+ margin-left: 16upx;
|
|
|
+ font-size: 26upx;
|
|
|
+ color: #007aff;
|
|
|
}
|
|
|
}
|
|
|
.btn-wrap {
|