【易售小程序项目】”我的“界面实现+“信息修改“界面实现+登出账号实现+图片上传组件【基于若依管理系统开发】

本文涉及的产品
对象存储 OSS,20GB 3个月
对象存储 OSS,恶意文件检测 1000次 1年
对象存储 OSS,内容安全 1000次 1年
简介: 【易售小程序项目】”我的“界面实现+“信息修改“界面实现+登出账号实现+图片上传组件【基于若依管理系统开发】

界面实现

界面效果

我的

修改信息

修改信息

学校选择

校区选择

性别设置

“我的”界面实现

api

login.js

import httpRequest from '@/utils/request'
// 账号退出方法
export function logout() {
  return httpRequest.request({
    url: '/logout',
    method: 'post'
  })
}

logout方法用来向后端发起请求,让后端删除Redis中的登录token

user.js

import httpRequest from '@/utils/request'
// 查询用户个人信息Vo
export function getUserProfileVo() {
  return httpRequest.request({
    url: '/system/user/profile/vo',
    method: 'get'
  })
}
// 用户头像上传
export function uploadAvatar(data) {
  return httpRequest.request({
    url: '/system/user/profile/avatar',
    method: 'post',
    data: data
  })
}

页面

<template>
  <view class="container">
    <!-- 头像、昵称展示 -->
    <view class="userDisplay">
      <view class="avatar" @click="this.avatarChangeShow=true">
        <u--image :src="userInfo.avatar" width="60px" height="60px" @click="click" shape="circle"></u--image>
      </view>
      <view class="nameView">
        <view>
          <view style="font-weight: bold;font-size: 36rpx;color: #ffffff;">{{userInfo.nickName}}</view>
          <view style="font-size: 30rpx;display: flex;margin-top: 10rpx;color: #ffffff;">
            <text class="iconfont" style="margin-right: 7rpx;color: #ffffff;">&#xe654;</text>
            <text class="selfIntroductionText"> {{userInfo.selfIntroduction}}</text>
          </view>
        </view>
      </view>
    </view>
    <view class="userMessage">
      <view style="font-size: 18px;font-weight: bold; padding: 20rpx;">
        <text>我的信息</text>
      </view>
      <u-cell-group>
        <u-cell name="userName" :value="userInfo.userName" :isLink="true"
          @click="editMessage('userName',userInfo.userName,'用户名')">
          <view slot="title" class="u-slot-title">
            <text class="iconfont" style="margin-right: 7rpx;">&#xe605;</text>
            <text class="u-cell-text">用户名</text>
          </view>
        </u-cell>
        <u-cell name="nickName" :value="userInfo.nickName" :isLink="true"
          @click="editMessage('nickName',userInfo.nickName,'昵称')">
          <view slot="title" class="u-slot-title">
            <text class="iconfont" style="margin-right: 7rpx;">&#xe605;</text>
            <text class="u-cell-text">昵称</text>
          </view>
        </u-cell>
        <u-cell name="avatar" :isLink="true" @click="editMessage('avatar',userInfo.avatar,'头像')">
          <view slot="title" class="u-slot-title">
            <text class="iconfont" style="margin-right: 7rpx;">&#xe60d;</text>
            <text class="u-cell-text">头像</text>
          </view>
        </u-cell>
        <u-cell name="schoolName" :value="userInfo.schoolName" :isLink="true"
          @click="editMessage('schoolId',userInfo.schoolName,'大学',userInfo.schoolId)">
          <view slot="title" class="u-slot-title">
            <text class="iconfont" style="margin-right: 7rpx;">&#xe916;</text>
            <text class="u-cell-text">大学</text>
          </view>
        </u-cell>
        <u-cell name="campusName" :value="userInfo.campusName" :isLink="true"
          @click="editMessage('campusId',userInfo.campusName,'校区',userInfo.campusId,userInfo.schoolId)">
          <view slot="title" class="u-slot-title">
            <text class="iconfont" style="margin-right: 7rpx;">&#xe628;</text>
            <text class="u-cell-text">校区</text>
          </view>
        </u-cell>
        <u-cell name="sex" :value="sexName" :isLink="true" @click="editMessage('sex',userInfo.sex,'性别')">
          <view slot="title" class="u-slot-title">
            <text class="iconfont" style="margin-right: 7rpx;">&#xe614;</text>
            <text class="u-cell-text">性别</text>
          </view>
        </u-cell>
        <u-cell name="email" :value="userInfo.email" :isLink="true"
          @click="editMessage('email',userInfo.email,'邮箱')">
          <view slot="title" class="u-slot-title">
            <text class="iconfont" style="margin-right: 7rpx;">&#xe672;</text>
            <text class="u-cell-text">邮箱</text>
          </view>
        </u-cell>
        <u-cell name="contactInformation" :isLink="true"
          @click="editMessage('contactInformation',userInfo.contactInformation,'联系方式')">
          <view slot="title" class="u-slot-title">
            <text class="iconfont" style="margin-right: 7rpx;">&#xe637;</text>
            <text class="u-cell-text">联系方式</text>
          </view>
        </u-cell>
        <u-cell name="selfIntroduction" :isLink="true"
          @click="editMessage('selfIntroduction',userInfo.selfIntroduction,'自我介绍')">
          <view slot="title" class="u-slot-title">
            <text class="iconfont" style="margin-right: 7rpx;">&#xe654;</text>
            <text class="u-cell-text">自我介绍</text>
          </view>
        </u-cell>
        <u-cell name="password" :isLink="true" @click="editMessage('password','-1','修改密码')">
          <view slot="title" class="u-slot-title">
            <text class="iconfont" style="margin-right: 7rpx;">&#xe603;</text>
            <text class="u-cell-text">修改密码</text>
          </view>
        </u-cell>
        <u-cell :isLink="true" @click="logout()">
          <view slot="title" class="u-slot-title">
            <text class="iconfont" style="margin-right: 7rpx;">&#xe659;</text>
            <text class="u-cell-text">退出账号</text>
          </view>
        </u-cell>
      </u-cell-group>
    </view>
  </view>
</template>
<script>
  import {
    logout
  } from "@/api/login";
  import {
    getUserProfileVo
  } from "@/api/user";
  export default {
    data() {
      return {
        userInfo: {
          avatar: '',
          nickName: "你好呀",
          userName: "admin",
          schoolName: "XX大学",
          campusName: "XX学院",
          sex: 0,
          selfIntroduction: "自我介绍,打撒活动啊速宏达搜好滴傻大搜到阿斯顿撒旦好骚",
          contactInformation: "联系方式",
          email: "32136712361@qq.com"
        },
        sexName: '其他',
      }
    },
    created() {
      this.getUserProfile();
    },
    methods: {
      editMessage(editKey, currentValue, editName, valueId = 0, schoolId = 0) {
        uni.navigateTo({
          url: "/pages/my/prodileEdit?editKey=" + editKey + "&currentValue=" + currentValue +
            "&editName=" + editName + "&valueId=" + valueId + "&schoolId=" + schoolId
        })
      },
      /**
       * 登出账号
       */
      logout() {
        // console.log("退出账号:")
        logout().then(res => {
          // console.log("退出账号:" + JSON.stringify(res));
          // 清除所有缓存
          uni.clearStorageSync();
          // 跳转到登录页
          uni.redirectTo({
            url: "/pages/login/login"
          })
        })
      },
      /**
       * 获取用户信息
       */
      getUserProfile() {
        getUserProfileVo().then(res => {
          // console.log("getUserProfile:" + JSON.stringify(res));
          this.userInfo = res.data;
          this.sexName = this.getSexName(this.userInfo.sex);
          // console.log("this.userInfo.sex:" + this.userInfo.sex + ",this.sexName:" + this.sexName);
          // console.log("this.userInfo:" + JSON.stringify(this.userInfo));
        })
      },
      getSexName(type) {
        if (type == 0) {
          return "男";
        } else if (type == 1) {
          return "女";
        } else if (type == 2) {
          return "其他";
        }
      }
    }
  }
</script>
<style lang="scss">
  .container {
    background: #F4F5F7;
    min-height: 100vh;
    .userDisplay {
      display: flex;
      padding: 20rpx;
      background: #2B92FF;
      .avatar {
        display: flex;
        justify-content: center;
        align-items: center;
        margin-right: 30rpx;
        background: #ffffff;
        border-radius: 50%;
        padding: 3px;
      }
      .nameView {
        display: flex;
        justify-content: center;
        align-items: center;
        .selfIntroductionText {
          overflow: hidden;
          text-overflow: ellipsis;
          display: -webkit-box;
          /* 显示1行 */
          -webkit-line-clamp: 1;
          -webkit-box-orient: vertical;
        }
      }
    }
    .userMessage {
      margin: 30rpx 30rpx;
      background: #FFFFFF;
      border-radius: 20rpx;
    }
  }
</style>
退出账号

退出账号需要做三件事,分别是:

  1. 调用后端接口,让其清除Redis中的token
  2. 小程序清除客户端的token缓存
  3. 重新跳转到登录页面
/**
* 登出账号
 */
logout() {
  logout().then(res => {
    // 清除所有缓存
    uni.clearStorageSync();
    // 跳转到登录页
    uni.redirectTo({
      url: "/pages/login/login"
    })
  })
},
让自我介绍只显示一行,结尾多余的字使用…代替
.selfIntroductionText {
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  /* 显示1行 */
  -webkit-line-clamp: 1;
  -webkit-box-orient: vertical;
}

跳转到信息修改页面
editMessage(editKey, currentValue, editName, valueId = 0, schoolId = 0) {
  uni.navigateTo({
    url: "/pages/my/prodileEdit?editKey=" + editKey + "&currentValue=" + currentValue +
      "&editName=" + editName + "&valueId=" + valueId + "&schoolId=" + schoolId
  })
},

所有信息的修改都在prodileEdit页面完成,跳转的时候需要携带一些参数,prodileEdit页面根据路由携带的参数来判断是修改什么信息,进而执行不同的代码

valueId = 0指的是,如果valueId没有接收到传值,就赋予默认值0

信息修改界面实现

api

user.js

import httpRequest from '@/utils/request'
// 修改用户个人信息
export function updateUserProfile(data) {
  return httpRequest.request({
    url: '/system/user/profile',
    method: 'put',
    data: data
  })
}
// 用户密码重置
export function updateUserPwd(oldPassword, newPassword) {
  const data = {
    oldPassword,
    newPassword
  }
  return httpRequest.request({
    url: '/system/user/profile/updatePwd',
    method: 'put',
    data: data
  })
}

school.js

import httpRequest from '@/utils/request'
// 查询学校列表
export function listSchool(query) {
  return httpRequest.request({
    url: '/market/school/list',
    method: 'post',
    data: query
  })
}

campus.js

import httpRequest from '@/utils/request'
// 查询校区列表
export function listCampus(query) {
  return httpRequest.request({
    url: '/market/campus/list',
    method: 'post',
    data: query
  })
}

logout方法在上面有了,这里就不重复写了,两个页面都调用了账号退出的逻辑,按理说应该单独写一个工具js来封装一个方法的,这样不同页面直接调用即可,可以减少代码的冗余,但是我看只有两个页面调用,而且代量也不多,于是就偷懒了

页面

<template>
  <view class="container">
    <u-toast ref="uToast"></u-toast>
    <!-- 设置头像 -->
    <view v-if="editUser.editKey==='avatar'">
      <imageUpload v-model="picList"></imageUpload>
    </view>
    <!-- 设置学校 -->
    <view v-else-if="editUser.editKey==='schoolId'">
      <view style="align-items: center;background:#2B92FF ;padding: 20rpx;border-radius: 10rpx;">
        <view
          style="border: 2rpx solid white ;border-radius: 10rpx;width:100%;display: flex;align-items: center;background:#ffffff ;">
          <u-search placeholder="请输入搜索内容" v-model="schoolId" @custom="seachSchool"></u-search>
        </view>
        <view style="margin: 10px;"></view>
        <view @click="this.selectSchoolShow = true"
          style="border: 2rpx solid white ;border-radius: 10rpx;width:100%;display: flex;align-items: center;background:#ffffff ;">
          <text style="margin: 5px;width: 55px;">
            学校
          </text>
          <view
            style="padding: 0px 5px; background:#F2F2F2;border-radius: 3px;width: 100%;margin-right: 5px;">
            {{editUser.currentValue}}
          </view>
        </view>
      </view>
      <u-picker :show="selectSchoolShow" :columns="schoolOptions" keyName="name" @cancel="closeSchoolSelect"
        @confirm="confirmSchoolSelect">
      </u-picker>
    </view>
    <!-- 设置校区 -->
    <view v-else-if="editUser.editKey==='campusId'">
      <view style="align-items: center;background:#2B92FF ;padding: 20rpx;border-radius: 10rpx;">
        <view @click="this.selectCampusShow = true"
          style="border: 2rpx solid white ;border-radius: 10rpx;width:100%;display: flex;align-items: center;background:#ffffff ;">
          <text style="margin: 5px;width: 55px;">
            校区
          </text>
          <view
            style="padding: 0px 5px; background:#F2F2F2;border-radius: 3px;width: 100%;margin-right: 5px;">
            {{editUser.currentValue}}
          </view>
        </view>
      </view>
      <u-picker :show="selectCampusShow" :columns="campusOptions" keyName="name" @cancel="closeCampusSelect"
        @confirm="confirmCampusSelect">
      </u-picker>
    </view>
    <!-- 设置性别 -->
    <view v-else-if="editUser.editKey==='sex'">
      <u-radio-group v-model="sexName" placement="column">
        <u-radio :customStyle="{marginBottom: '8px'}" v-for="(item, index) in sexList" :key="index"
          :label="item.name" :name="item.name" @change="sexChange">
        </u-radio>
      </u-radio-group>
    </view>
    <!-- 修改密码 -->
    <view v-else-if="editUser.editKey==='password'">
      <u--form :model="editPasswordForm" ref="editPasswordForm">
        <u-form-item label="输入原密码" :prop="editPasswordForm.oldPassword" borderBottom="true" labelWidth="80">
          <u-input v-model="editPasswordForm.oldPassword" password />
        </u-form-item>
        <u-form-item label="输入新密码" :prop="editPasswordForm.newPassword1" borderBottom="true" labelWidth="80">
          <u-input v-model="editPasswordForm.newPassword1" password />
        </u-form-item>
        <u-form-item label="再次输入新密码" :prop="editPasswordForm.newPassword2" borderBottom="true" labelWidth="80">
          <u-input v-model="editPasswordForm.newPassword2" password />
        </u-form-item>
      </u--form>
      <view style="margin: 10px;"></view>
      <u-button type="primary" @click="resetPassword" style="width: 90%;">提交</u-button>
    </view>
    <!-- 设置其他信息 -->
    <view v-else>
      <u--form :model="editUser" ref="uForm">
        <u-form-item :label="editUser.editName" :prop="editUser.editKey" borderBottom="true" labelWidth="80">
          <u--textarea v-if="editUser.editKey=='contactInformation'||editUser.editKey=='selfIntroduction'"
            v-model="editUser.currentValue" placeholder="请输入内容" autoHeight count
            maxlength='250'></u--textarea>
          <u-input v-else v-model="editUser.currentValue" />
        </u-form-item>
      </u--form>
    </view>
    <view style="margin: 10px;" v-if="editUser.editKey!='password'"></view>
    <u-button type="primary" @click="updateUserProfile" style="width: 90%;"
      v-if="editUser.editKey!='password'">提交</u-button>
    </u-picker>
  </view>
</template>
<script>
  import {
    updateUserProfile,
    updateUserPwd
  } from "@/api/user";
  import {
    listSchool
  } from "@/api/schoolMessage/school.js";
  import {
    listCampus
  } from "@/api/schoolMessage/campus.js";
  import {
    logout
  } from "@/api/login";
  import imageUpload from "@/components/ImageUpload/ImageUpload.vue";
  export default {
    components: {
      imageUpload
    },
    data() {
      return {
        editUser: {},
        /// 学校选择
        selectSchoolShow: false,
        schoolOptions: [],
        // 搜索学校名称
        schoolId: '',
        schoolQueryParams: {
          name: ''
        },
        /// 校区选择
        campusId: '',
        campusOptions: [],
        selectCampusShow: false,
        /// 性别选择
        sexList: [{
            name: '男',
            disabled: false
          },
          {
            name: '女',
            disabled: false
          },
          {
            name: '其他',
            disabled: false
          }
        ],
        sexName: "其他",
        // 图片集合
        picList: [],
        /// 修改密码
        editPasswordForm: {
          oldPassword: '',
          newPassword1: '',
          newPassword2: ''
        }
      }
    },
    created() {
    },
    // 获取路由的参数
    onLoad(e) {
      // console.log("e:" + JSON.stringify(e));
      if (e) {
        this.editUser = {
          editKey: e.editKey,
          currentValue: e.currentValue,
          editName: e.editName,
          valueId: e.valueId,
          schoolId: e.schoolId
        };
        if (e.editKey === 'schoolId') {
          this.getSchoolList();
        } else if (e.editKey === 'campusId') {
          this.getCampusList();
        } else if (e.editKey === 'sex') {
          this.sexName = this.getSexName(e.currentValue);
        } else if (e.editKey === 'avatar') {
          this.picList.push(e.currentValue);
          // console.log("this.picList:" + JSON.stringify(this.picList));
        }
      }
    },
    methods: {
      updateUserProfile() {
        let updateUser = {};
        if (this.editUser.editKey === 'schoolId' || this.editUser.editKey === 'campusId') {
          updateUser = {
            [this.editUser.editKey]: this.editUser.valueId
          };
        } else if (this.editUser.editKey === 'avatar') {
          updateUser = {
            [this.editUser.editKey]: this.picList[0]
          };
        } else {
          updateUser = {
            [this.editUser.editKey]: this.editUser.currentValue
          };
        }
        // console.log("updateUser:" + JSON.stringify(updateUser));
        updateUserProfile(updateUser).then(res => {
          // 修改成功,返回之前的页面
          uni.reLaunch({
            url: "/pages/my/my"
          })
          this.$refs.uToast.show({
            type: 'success',
            message: "修改成功"
          })
        }).catch(res => {
          // console.log("响应出错");
          // console.log("res:" + JSON.stringify(res));
          this.$refs.uToast.show({
            type: 'error',
            message: res.msg
          })
        })
      },
      /**
       * 修改密码
       */
      resetPassword() {
        let isSame = this.editPasswordForm.newPassword1 === this.editPasswordForm.newPassword2;
        if (isSame == false) {
          this.$refs.uToast.show({
            type: 'error',
            message: '两次输入的新密码不同,请重新输入'
          })
        } else if (this.editPasswordForm.newPassword1.length < 6) {
          this.$refs.uToast.show({
            type: 'error',
            message: '新密码长度小于6个字符,请重新输入'
          })
        } else {
          updateUserPwd(this.editPasswordForm.oldPassword, this.editPasswordForm.newPassword1).then(res => {
            this.$refs.uToast.show({
              type: 'success',
              message: '密码修改成功,即将退出账号,请重新登录'
            })
            setTimeout(() => {
              this.logout();
            }, 2000)
          }).catch(res => {
            this.$refs.uToast.show({
              type: 'error',
              message: res.msg
            })
          })
        }
      },
      getSchoolList() {
        listSchool(this.schoolQueryParams).then(res => {
          this.schoolOptions = [];
          this.schoolOptions.push(res.rows);
          // console.log("this.schoolOptions:" + JSON.stringify(this.schoolOptions));
        })
      },
      /**
       * 搜索学校
       */
      seachSchool() {
        this.schoolQueryParams.name = this.schoolId;
        // console.log("this.schoolQueryParams:"+JSON.stringify(this.schoolQueryParams))
        this.getSchoolList();
        this.selectSchoolShow = true;
      },
      /**
       * 关闭学校选择
       */
      closeSchoolSelect() {
        // console.log("closeSchoolSelect")
        this.selectSchoolShow = false;
      },
      /**
       * 确定选择学校
       */
      confirmSchoolSelect(e) {
        this.editUser.valueId = e.value[0].id;
        this.editUser.currentValue = e.value[0].name;
        // console.log("this.editUser.schoolId:" + this.editUser.schoolId);
        this.selectSchoolShow = false;
      },
      getCampusList() {
        let CampusQueryParams = {
          schoolId: this.editUser.schoolId
        }
        listCampus().then(res => {
          this.campusOptions = [];
          this.campusOptions.push(res.rows);
          // console.log("this.schoolOptions:" + JSON.stringify(this.schoolOptions));
        })
      },
      /**
       * 关闭校区选择
       */
      closeCampusSelect() {
        // console.log("closeSchoolSelect")
        this.selectCampusShow = false;
      },
      /**
       * 确定选择校区
       */
      confirmCampusSelect(e) {
        this.editUser.valueId = e.value[0].id;
        this.editUser.currentValue = e.value[0].name;
        // console.log("this.editUser.schoolId:" + this.editUser.schoolId);
        this.selectCampusShow = false;
      },
      /**
       * 修改性别
       */
      sexChange(e) {
        // console.log("sexChange:" + JSON.stringify(e));
        if (e == "男") {
          this.editUser.currentValue = 0;
        } else if (e == "女") {
          this.editUser.currentValue = 1;
        } else if (e == "其他") {
          this.editUser.currentValue = 2;
        }
      },
      getSexName(type) {
        if (type == 0) {
          return "男";
        } else if (type == 1) {
          return "女";
        } else if (type == 2) {
          return "其他";
        }
      },
      /**
       * 登出账号
       */
      logout() {
        console.log("退出账号:")
        logout().then(res => {
          console.log("退出账号:" + JSON.stringify(res));
          // 清除所有缓存
          uni.clearStorageSync();
          // 跳转到首页
          uni.redirectTo({
            url: "/pages/login/login"
          })
        })
      },
    }
  }
</script>
<style lang="scss">
  .container {
    padding: 20px;
  }
</style>
动态给对象设置属性名和值
updateUser = {
  [this.editUser.editKey]: this.editUser.valueId
};
修改密码
/**
* 修改密码
 */
resetPassword() {
  let isSame = this.editPasswordForm.newPassword1 === this.editPasswordForm.newPassword2;
  if (isSame == false) {
    this.$refs.uToast.show({
      type: 'error',
      message: '两次输入的新密码不同,请重新输入'
    })
  } else if (this.editPasswordForm.newPassword1.length < 6) {
    this.$refs.uToast.show({
      type: 'error',
      message: '新密码长度小于6个字符,请重新输入'
    })
  } else {
    updateUserPwd(this.editPasswordForm.oldPassword, this.editPasswordForm.newPassword1).then(res => {
      this.$refs.uToast.show({
        type: 'success',
        message: '密码修改成功,即将退出账号,请重新登录'
      })
      setTimeout(() => {
        this.logout();
      }, 2000)
    }).catch(res => {
      this.$refs.uToast.show({
        type: 'error',
        message: res.msg
      })
    })
  }
},

在修改密码之前,前端需要做一些数据校验,来减轻后台的工作压力,如提前将不合法的密码拦截,不让其提交。我这里只是做了最简单的校验,还可以使用正则表达式做一些复杂的密码校验,如密码必须包含英文、数字、符号

图片上传组件
<template>
  <view>
    <u-loading-page :loading="uploading" loading-text="图片上传中..."></u-loading-page>
    <u-upload :fileList="fileList1" @afterRead="afterRead" @delete="deletePic" name="1" multiple
      :maxCount="maxCount" :previewFullImage="true"></u-upload>
  </view>
</template>
<script>
  import ossApi from "@/api/thirdParty/oss.js";
  import uuidApi from "@/utils/uuid.js"
  export default {
    name: "ImageUpload",
    props: {
      value: [String, Object, Array],
      // 图片最大上传数量
      maxCount: {
        type: Number,
        default: 1
      }
    },
    data() {
      return {
        fileList1: [],
        uploadUrl: "http://smart-scheduling-system-13184.oss-cn-beijing.aliyuncs.com",
        // 图片数量
        pictureNum: 0,
        // 是否显示加载中
        uploading: false,
      };
    },
    created() {
      // console.log("this.value:" + JSON.stringify(this.value))
      if (this.value != null) {
        this.fileList1 = [];
        for (var i = 0; i < this.value.length; i++) {
          if (this.value[i] != '') {
            this.fileList1.push({
              url: this.value[i]
            });
          }
        }
      }
      this.pictureNum = this.fileList1.length;
      // console.log("this.fileList1:" + JSON.stringify(this.fileList1))
    },
    watch: {
      // 监听数据变化
      value: {
        handler(newValue, oldValue) {
          this.fileList1 = [];
          for (var i = 0; i < newValue.length; i++) {
            if (newValue[i] != '') {
              this.fileList1.push({
                url: newValue[i]
              });
            }
          }
          this.pictureNum = this.fileList1.length;
        },
        immediate: true,
      }
    },
    methods: {
      // 删除图片
      deletePic(event) {
        let deletIndex = event.index;
        this[`fileList${event.name}`].splice(deletIndex, 1);
        let urlList = [];
        for (var i = 0; i < this.fileList1.length; i++) {
          urlList.push(this.fileList1[i].url);
        }
        this.$emit("input", urlList);
        this.pictureNum--;
      },
      // 新增图片
      async afterRead(event) {
        // 当设置 multiple 为 true 时, file 为数组格式,否则为对象格式
        let lists = [].concat(event.file)
        let fileListLen = this[`fileList${event.name}`].length
        lists.map((item) => {
          this[`fileList${event.name}`].push({
            ...item,
            status: 'uploading',
            message: '上传中'
          })
        })
        for (let i = 0; i < lists.length; i++) {
          const result = await this.uploadFilePromise(lists[i].url)
          let item = this[`fileList${event.name}`][fileListLen]
          this[`fileList${event.name}`].splice(fileListLen, 1, Object.assign(item, {
            status: 'success',
            message: '',
            url: result
          }))
          fileListLen++
        }
      },
      // 上传图片
      uploadFilePromise(url) {
        this.uploading = true;
        return new Promise((resolve, reject) => {
          let dataObj = {
            policy: '',
            signature: '',
            key: '',
            OSSAccessKeyId: '',
            dir: '',
            host: ''
          };
          ossApi.getPolicy()
            .then((response) => {
              // console.log('policy response:' + JSON.stringify(response))
              // debugger;
              dataObj.policy = response.data.policy
              dataObj.signature = response.data.signature
              dataObj.OSSAccessKeyId = response.data.accessId
              dataObj.key = response.data.dir + uuidApi.getUUID() + '_${filename}'
              dataObj.dir = response.data.dir
              dataObj.host = response.data.host
              // console.log('获取policy成功')
              let a = uni.uploadFile({
                url: this.uploadUrl,
                filePath: url,
                name: 'file',
                formData: dataObj,
                success: (res) => {
                  console.log('图片上传成功,url:' + JSON.stringify(url));
                  // 拼接出可以直接访问的oss图片 "http://tmp/":windows电脑的前缀 "wxfile://":安卓微信的前缀
                  let picUrl = dataObj.host +
                    '/' +
                    dataObj.key.replace('${filename}', url.indexOf(
                      "http://tmp/") != -1 ? url.replace(
                      "http://tmp/", '') : url.replace(
                      "wxfile://", ''));
                  // console.log('picUrl:' + JSON.stringify(picUrl));
                  console.log('this.fileList1:' + JSON.stringify(this
                    .fileList1));
                  console.log('this.pictureNum:' + this.pictureNum);
                  // 设置之后,才可以预览图片
                  this.fileList1[this.fileList1.length - (this.fileList1.length -
                    this.pictureNum)].url = picUrl;
                  this.pictureNum++;
                  let urlList = [];
                  for (var i = 0; i < this.fileList1.length; i++) {
                    urlList.push(this.fileList1[i].url);
                  }
                  // console.log("urlList:" + JSON.stringify(urlList))
                  this.$emit("input", urlList);
                  setTimeout(() => {
                    resolve(res)
                  }, 1000)
                }
              });
              this.uploading = false;
              resolve(true)
            })
            .catch((err) => {
              // console.log('获取policy失败')
              reject(false)
            })
        })
      },
    }
  }
</script>
<style>
</style>

OSS后端代码和讲解可以参考OSS对象存储后端实现+Vue实现图片上传【基于若依管理系统开发】

通过定义在props中定义value属性,并结合this.$emit("input", 值);方法,可以将值同步给组件v-model所绑定的变量

<imageUpload v-model="picList"></imageUpload>

注意:imageUpload 接收的属性需要是一个图片url数组

部分后端代码

后端基于若依后端管理系统开发,很多接口在系统中已经内置,或者可以直接通过系统的生成器生成出来,这里就不再贴上来,只贴部分基于系统已有接口修改而来的接口,避免读者迷惑

Controller

/**
 * 修改用户
 */
@Log(title = "个人信息", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult updateProfile(@RequestBody SysUser user) {
    LoginUser loginUser = getLoginUser();
    SysUser sysUser = loginUser.getUser();
    if (StringUtils.isNotEmpty(user.getUserName()) && !userService.checkUserNameUnique(user)) {
        return error("修改用户 '" + sysUser.getUserName() + "' 失败,用户名已存在");
    }
    if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) {
        return error("修改用户 '" + sysUser.getUserName() + "' 失败,手机号码已存在");
    }
    if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) {
        return error("修改用户 '" + sysUser.getUserName() + "' 失败,邮箱账号已存在");
    }
    user.setUserId(sysUser.getUserId());
    user.setPassword(null);
//        user.setAvatar(null);
    user.setDeptId(null);
    if (userService.updateUserProfile(user) > 0) {
        // 更新缓存用户信息
        sysUser.setUserName(user.getUserName());
        sysUser.setNickName(user.getNickName());
        sysUser.setPhonenumber(user.getPhonenumber());
        sysUser.setEmail(user.getEmail());
        sysUser.setSex(user.getSex());
        tokenService.setLoginUser(loginUser);
        return success();
    }
    return error("修改个人信息异常,请联系管理员");
}
 /**
  * 重置密码
  */
 @Log(title = "个人信息", businessType = BusinessType.UPDATE)
 @PutMapping("/updatePwd")
 public AjaxResult updatePwd(@RequestBody Map<String, String> map) {
     LoginUser loginUser = getLoginUser();
     String userName = loginUser.getUsername();
     String password = loginUser.getPassword();
     String oldPassword = map.get("oldPassword");
     String newPassword = map.get("newPassword");
     if (!SecurityUtils.matchesPassword(oldPassword, password)) {
         return error("修改密码失败,旧密码错误");
     }
     if (SecurityUtils.matchesPassword(newPassword, password)) {
         return error("新密码不能与旧密码相同");
     }
     if (userService.resetUserPwd(userName, SecurityUtils.encryptPassword(newPassword)) > 0) {
         // 更新缓存用户密码
         loginUser.getUser().setPassword(SecurityUtils.encryptPassword(newPassword));
         tokenService.setLoginUser(loginUser);
         return success();
     }
     return error("修改密码异常,请联系管理员");
 }
相关实践学习
借助OSS搭建在线教育视频课程分享网站
本教程介绍如何基于云服务器ECS和对象存储OSS,搭建一个在线教育视频课程分享网站。
目录
相关文章
|
15天前
|
小程序 前端开发 API
小程序全栈开发中的多端适配与响应式布局
【4月更文挑战第12天】本文探讨了小程序全栈开发中的多端适配与响应式布局。多端适配涉及平台和设备适应,确保统一用户体验;响应式布局利用媒体查询和弹性布局维持不同设备的布局一致性。实践中,开发者可借助跨平台框架实现多平台开发,运用响应式布局技术适应不同设备。同时,注意兼容性、性能优化和用户体验,以提升小程序质量和用户体验。通过这些方法,开发者能更好地掌握小程序全栈开发。
|
15天前
|
小程序 前端开发 API
微信小程序全栈开发中的异常处理与日志记录
【4月更文挑战第12天】本文探讨了微信小程序全栈开发中的异常处理和日志记录,强调其对确保应用稳定性和用户体验的重要性。异常处理涵盖前端(网络、页面跳转、用户输入、逻辑异常)和后端(数据库、API、业务逻辑)方面;日志记录则关注关键操作和异常情况的追踪。实践中,前端可利用try-catch处理异常,后端借助日志框架记录异常,同时采用集中式日志管理工具提升分析效率。开发者应注意安全性、性能和团队协作,以优化异常处理与日志记录流程。
|
15天前
|
小程序 安全 数据安全/隐私保护
微信小程序全栈开发中的身份认证与授权机制
【4月更文挑战第12天】本文探讨了微信小程序全栈开发中的身份认证与授权机制。身份认证包括手机号验证、微信登录和第三方登录,而授权机制涉及角色权限控制、ACL和OAuth 2.0。实践中,开发者可利用微信登录获取用户信息,集成第三方登录,以及实施角色和ACL进行权限控制。注意点包括安全性、用户体验和合规性,以保障小程序的安全运行和良好体验。通过这些方法,开发者能有效掌握小程序全栈开发技术。
|
15天前
|
小程序 前端开发 安全
小程序全栈开发中的跨域问题及其解决方案
【4月更文挑战第12天】本文探讨了小程序全栈开发中的跨域问题及其解决方案。跨域问题源于浏览器安全策略,主要体现在前后端分离、第三方服务集成和数据共享上。为解决此问题,开发者可采用CORS、JSONP、代理服务器、数据交换格式和域名策略等方法。实践中需注意安全性、兼容性和性能。通过掌握这些解决方案,开发者能更好地处理小程序的跨域问题,提升用户体验。
|
15天前
|
小程序 前端开发 JavaScript
微信小程序全栈开发中的PWA技术应用
【4月更文挑战第12天】本文探讨了微信小程序全栈开发中PWA技术的应用,PWA结合Web的开放性和原生应用的性能,提供离线访问、后台运行、桌面图标和原生体验。开发者可利用Service Worker实现离线访问,Worker处理后台运行,Web App Manifest添加桌面图标,CSS和JavaScript提升原生体验。实践中需注意兼容性、性能优化和用户体验。PWA技术能提升小程序的性能和用户体验,助力开发者打造优质小程序。
|
8天前
|
小程序 JavaScript Java
基于SpringBoot+Vue+uniapp微信小程序的教师管理系统的详细设计和实现
基于SpringBoot+Vue+uniapp微信小程序的教师管理系统的详细设计和实现
36 2
|
8天前
|
小程序 JavaScript Java
基于SpringBoot+Vue+uniapp微信小程序的学生公寓电费信息的详细设计和实现
基于SpringBoot+Vue+uniapp微信小程序的学生公寓电费信息的详细设计和实现
32 1
|
8天前
|
小程序 JavaScript Java
基于SpringBoot+Vue+uniapp微信小程序的健身管理系统及会员微信小程序的详细设计和实现
基于SpringBoot+Vue+uniapp微信小程序的健身管理系统及会员微信小程序的详细设计和实现
30 0
|
15天前
|
JavaScript 前端开发 小程序
微信小程序全栈开发之性能优化策略
【4月更文挑战第12天】本文探讨了微信小程序全栈开发的性能优化策略,包括前端的资源和渲染优化,如图片压缩、虚拟DOM、代码分割;后端的数据库和API优化,如索引创建、缓存使用、RESTful API设计;以及服务器的负载均衡和CDN加速。通过这些方法,开发者可提升小程序性能,优化用户体验,增强商业价值。
|
1月前
|
小程序 API
点餐小程序实战教程09-订单功能开发
点餐小程序实战教程09-订单功能开发