SpringBoot+SpringSecurity+MybatisPlus+Vue3小项目摘录(八)

文章目录

个人中心的页面实现

按照左右两部分的布局划分即可

提示:这里可以主体参考elementplus官网的Layout布局实现https://element-plus.gitee.io/zh-CN/component/layout.html

在这里插入图片描述

修改views/userCenter/index.vue文件
<template>
  <div class="app-container">
    <el-row :gutter="20">
      <el-col :span="6">
        <el-card class="box-card">
               <template v-slot:header>
                 <div class="clearfix">
                   <span>个人信息</span>
                 </div>
               </template>
               <div>
                  <div class="text-center">
                     <avatar :user="currentUser"/>
                  </div>
                  <ul class="list-group list-group-striped">
                     <li class="list-group-item">
                        <svg-icon icon="user" />&nbsp;&nbsp;用户名称
                        <div class="pull-right">{{currentUser.username}}</div>
                     </li>
                     <li class="list-group-item">
                        <svg-icon icon="phone" />&nbsp;&nbsp;手机号码
                        <div class="pull-right">{{currentUser.phonenumber}}</div>
                     </li>
                     <li class="list-group-item">
                        <svg-icon icon="email" />&nbsp;&nbsp;用户邮箱
                        <div class="pull-right">{{currentUser.email}}</div>
                     </li>
                     <li class="list-group-item">
                        <svg-icon icon="peoples" />&nbsp;&nbsp;所属角色
                        <div class="pull-right">{{currentUser.roles}}</div>
                     </li>
                     <li class="list-group-item">
                        <svg-icon icon="date" />&nbsp;&nbsp;创建日期
                        <div class="pull-right">{{formatDate(currentUser.loginDate)}}</div>
                     </li>
                  </ul>
               </div>
            </el-card>
      </el-col>
      <el-col :span="18">
          <el-card>
               <template v-slot:header>
                 <div class="clearfix">
                   <span>基本资料</span>
                 </div>
               </template>
               <el-tabs v-model="activeTab">
                  <el-tab-pane label="基本资料" name="userinfo">
                      基本资料信息
                  </el-tab-pane>
                  <el-tab-pane label="修改密码" name="resetPwd">
                      修改密码信息
                  </el-tab-pane>
               </el-tabs>
            </el-card>
        </el-col>

    </el-row>
  </div>
</template>

<script setup>
import {ref} from 'vue'
import store from '@/store'
import { formatDate } from '@/util/formatDate.js'

const currentUser = ref(store.getters.GET_USERINFO);

const activeTab = ref("userinfo");

</script>

<style lang="scss" scoped>

.list-group-striped>.list-group-item {
  border-left: 0;
  border-right: 0;
  border-radius: 0;
  padding-left: 0;
  padding-right: 0;
}

.list-group-item {
  border-bottom: 1px solid #e7eaec;
  border-top: 1px solid #e7eaec;
  margin-bottom: -1px;
  padding: 11px 0;
  font-size: 13px;
}

.pull-right{
  float: right!important;
}

::v-deep .el-card__body{
  height:230px;
}

::v-deep .box-card{
  height:450px;
}
</style>


在util目录下新建处理时间的js【formatDate.js】
//方法一
export function formatDate(val) {
    var date = new Date(Number(val)); //时间戳为10位需*1000,时间戳为13位的话不需乘1000
    var Y = date.getFullYear() + "-";
    var M = (date.getMonth() + 1 < 10 ? "0" + (date.getMonth() + 1) : date.getMonth() + 1) + "-";
    var D = date.getDate() + " ";
    var h = date.getHours() + ":";
    var m = date.getMinutes() + ":";
    var s = (date.getSeconds() < 10 ? "0" + (date.getSeconds()) : date.getSeconds());
    return Y + M + D + h + m + s;
}

时间处理解析有很多的方式,按照你喜欢的方式使用即可!!!

预览效果:

在这里插入图片描述

在这里插入图片描述

所属的角色信息没有,需要修改后端的数据映射
  • 修改用户对象的属性【添加用户对应的角色信息属性】
    在这里插入图片描述
  • 修改登录成功的逻辑处理角色信息
    在这里插入图片描述在这里插入图片描述

组件细化处理

在这里插入图片描述

在userCenter目录下新建三个组件来对应三个内容

在这里插入图片描述

修改index.vue中的引入以及组件的使用

在这里插入图片描述

基本资料修改的实现

在这里插入图片描述

userInfo.vue组件内容的编写
<template>
<el-form ref="userRef" :model="form" :rules="rules" label-width="100px" >
      <el-form-item label="手机号码:" prop="phonenumber">
         <el-input v-model="form.phonenumber" maxlength="11" />
      </el-form-item>
      <el-form-item label="用户邮箱:" prop="email">
         <el-input v-model="form.email" maxlength="50" />
      </el-form-item>
      <el-form-item>
      <el-button type="primary" @click="handleSubmit">保存</el-button>

      </el-form-item>
   </el-form>
</template>

<script setup>
import {defineProps, ref} from "vue";
import requestUtil from "@/util/request";
import { ElMessage } from 'element-plus'
import store from "@/store";

const props=defineProps(
    {
      user:{
        type:Object,
        default:()=>{},
        required:true
      }
    }
)

const form=ref({
  id:-1,
  phonenumber:'',
  email:''
})

const userRef=ref(null)


const rules = ref({
  email: [{ required: true, message: "邮箱地址不能为空", trigger: "blur" }, { type: "email", message: "请输入正确的邮箱地址", trigger: ["blur", "change"] }],
  phonenumber: [{ required: true, message: "手机号码不能为空", trigger: "blur" }, { pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: "请输入正确的手机号码", trigger: "blur" }],
});

form.value=props.user;


修改信息的的事件:

在这里插入图片描述在这里插入图片描述

后端用户请求的控制器处理

如果之前已经在controller包中编写过SysUserController的需要注意,那么重命名,要么处理一下即可

在这里插入图片描述
在这里插入图片描述

页面内容:

在这里插入图片描述

数据表的变化:

在这里插入图片描述

代码规整:

个人中心userInfo.vue的组件页面:
<template>
<el-form ref="userRef" :model="form" :rules="rules" label-width="100px" >
      <el-form-item label="手机号码:" prop="phonenumber">
         <el-input v-model="form.phonenumber" maxlength="11" />
      </el-form-item>
      <el-form-item label="用户邮箱:" prop="email">
         <el-input v-model="form.email" maxlength="50" />
      </el-form-item>
      <el-form-item>
      <el-button type="primary" @click="handleSubmit">保存</el-button>

      </el-form-item>
   </el-form>
</template>

<script setup>
import {defineProps, ref} from "vue";
import requestUtil from "@/util/request";
import { ElMessage } from 'element-plus'
import store from "@/store";

const props=defineProps(
    {
      user:{
        type:Object,
        default:()=>{},
        required:true
      }
    }
)

const form=ref({
  id:-1,
  phonenumber:'',
  email:''
})

const userRef=ref(null)


const rules = ref({
  email: [{ required: true, message: "邮箱地址不能为空", trigger: "blur" }, { type: "email", message: "请输入正确的邮箱地址", trigger: ["blur", "change"] }],
  phonenumber: [{ required: true, message: "手机号码不能为空", trigger: "blur" }, { pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: "请输入正确的手机号码", trigger: "blur" }],
});

form.value=props.user;





const handleSubmit=()=>{

  userRef.value.validate(async (valid)=>{
    if(valid) {
      let result = await requestUtil.post("sys/user/save", form.value);
      let data = result.data;
      if (data.code == 200) {
        ElMessage.success("执行成功!")
        store.commit("SET_USERINFO", form.value)
      }
    }
  })
}


</script>

<style lang="scss" scoped>

</style>

后端控制器的编写:
需要在请求方法头部加以权限处理

在这里插入图片描述

@RestController
@RequestMapping("/sys/user")
public class SysUsersController {

    @Autowired
    private SysUserService sysUserService;


    /**
     * 添加或者修改
     * @param sysUser
     * @return
     */
    @PostMapping("/save")
    @PreAuthorize("hasAuthority('system:user:add')"+"||"+"hasAuthority('system:user:edit')")
    public ResponseData save(@RequestBody SysUser sysUser){
        if(sysUser.getId()==null || sysUser.getId()==-1){

        }else{
            //此处修改更新时间可以使用MybatisPlus中的自动填充策略去实现【解决硬编码问题】
            sysUser.setUpdateTime(new Date());
            sysUserService.updateById(sysUser);
        }
        return new ResponseData("操作成功",200);
    }
}

修改密码功能的实现

编写resetPwd.vue页面组件的内容

在这里插入图片描述

基本的效果如下:

在这里插入图片描述

表单校验的规则处理:

在这里插入图片描述

编写提交修改请求的事件处理:

在这里插入图片描述

整个代码示例可参考:【resetPwd.vue】
<template>
<el-form ref="pwdRef" :model="form" :rules="rules" label-width="80px">
        <el-form-item label="旧密码" prop="oldPassword">
           <el-input v-model="form.oldPassword" placeholder="请输入旧密码" type="password" show-password />
        </el-form-item>
        <el-form-item label="新密码" prop="newPassword">
           <el-input v-model="form.newPassword" placeholder="请输入新密码" type="password" show-password />
        </el-form-item>
        <el-form-item label="确认密码" prop="confirmPassword">
           <el-input v-model="form.confirmPassword" placeholder="请确认密码" type="password" show-password/>
        </el-form-item>
        <el-form-item>
        <el-button type="primary" @click="handleSubmit">保存</el-button>

        </el-form-item>
   </el-form>
</template>

<script setup>
import {defineProps, ref} from "vue";
import requestUtil from "@/util/request";
import { ElMessage } from 'element-plus'
import store from "@/store";

const props=defineProps(
    {
      user:{
        type:Object,
        default:()=>{},
        required:true
      }
    }
)

const form=ref({
  id:-1,
  oldPassword:'',
  newPassword:'',
  confirmPassword:''
})

const pwdRef=ref(null)

form.value=props.user;

const equalToPassword = (rule, value, callback) => {
  if (form.value.newPassword !== value) {
    callback(new Error("两次输入的密码不一致"));
  } else {
    callback();
  }
};

const rules = ref({
  oldPassword: [{ required: true, message: "旧密码不能为空", trigger: "blur" }],
  newPassword: [{ required: true, message: "新密码不能为空", trigger: "blur" }, { min: 3, max: 20, message: "长度在 3 到 20 个字符", trigger: "blur" }],
  confirmPassword: [{ required: true, message: "确认密码不能为空", trigger: "blur" }, { required: true, validator: equalToPassword, trigger: "blur" }]
});


const handleSubmit=()=>{

  pwdRef.value.validate(async (valid)=>{
    if(valid) {
      let result = await requestUtil.post("sys/user/updateUserPwd", form.value);
      let data = result.data;
      if (data.code == 200) {
        ElMessage.success("密码修改成功,下一次登录生效!")
        store.commit("SET_USERINFO", form.value)
      }else{
        ElMessage.error(data.msg)
      }
    }
  })
}

</script>

<style lang="scss" scoped>

</style>

后端处理
  • 修改用户实体对象的属性【需要与前端表单的属性进行映射对应到后端实体对象中】
    在这里插入图片描述
  • 控制器修改的请求方法编写
    在这里插入图片描述
测试一下:
①、当不输入内容或者没有符合校验规则时,有提示

在这里插入图片描述

②、如果输入的原密码错误时,有提示

在这里插入图片描述

③、当且仅当输入原密码以及校验通过时,才是正确的!!!

在这里插入图片描述

④、点击右上角安全退出之后,尝试用原来的密码登录(提示)以及使用修改后的密码登录

在这里插入图片描述
在这里插入图片描述

代码规整:

前端resetPwd.vue组件的内容:
<template>
<el-form ref="pwdRef" :model="form" :rules="rules" label-width="80px">
        <el-form-item label="旧密码" prop="oldPassword">
           <el-input v-model="form.oldPassword" placeholder="请输入旧密码" type="password" show-password />
        </el-form-item>
        <el-form-item label="新密码" prop="newPassword">
           <el-input v-model="form.newPassword" placeholder="请输入新密码" type="password" show-password />
        </el-form-item>
        <el-form-item label="确认密码" prop="confirmPassword">
           <el-input v-model="form.confirmPassword" placeholder="请确认密码" type="password" show-password/>
        </el-form-item>
        <el-form-item>
        <el-button type="primary" @click="handleSubmit">保存</el-button>

        </el-form-item>
   </el-form>
</template>

<script setup>
import {defineProps, ref} from "vue";
import requestUtil from "@/util/request";
import { ElMessage } from 'element-plus'
import store from "@/store";

const props=defineProps(
    {
      user:{
        type:Object,
        default:()=>{},
        required:true
      }
    }
)

const form=ref({
  id:-1,
  oldPassword:'',
  newPassword:'',
  confirmPassword:''
})

const pwdRef=ref(null)

form.value=props.user;

const equalToPassword = (rule, value, callback) => {
  if (form.value.newPassword !== value) {
    callback(new Error("两次输入的密码不一致"));
  } else {
    callback();
  }
};

const rules = ref({
  oldPassword: [{ required: true, message: "旧密码不能为空", trigger: "blur" }],
  newPassword: [{ required: true, message: "新密码不能为空", trigger: "blur" }, { min: 3, max: 20, message: "长度在 3 到 20 个字符", trigger: "blur" }],
  confirmPassword: [{ required: true, message: "确认密码不能为空", trigger: "blur" }, { required: true, validator: equalToPassword, trigger: "blur" }]
});


const handleSubmit=()=>{

  pwdRef.value.validate(async (valid)=>{
    if(valid) {
      let result = await requestUtil.post("sys/user/updateUserPwd", form.value);
      let data = result.data;
      if (data.code == 200) {
        ElMessage.success("密码修改成功,下一次登录生效!")
        store.commit("SET_USERINFO", form.value)
      }else{
        ElMessage.error(data.msg)
      }
    }
  })
}

</script>

<style lang="scss" scoped>

</style>

后端的控制器代码如下:
@RestController
@RequestMapping("/sys/user")
public class SysUsersController {

        @Autowired
        private SysUserService sysUserService;
    
        @Autowired
        private BCryptPasswordEncoder bCryptPasswordEncoder;

        /**
         * 修改密码
         * @param sysUser
         * @return
         */
        @PostMapping("/updateUserPwd")
        @PreAuthorize("hasAuthority('system:user:edit')")
        public ResponseData updateUserPwd(@RequestBody SysUser sysUser){
            SysUser currentUser = sysUserService.getById(sysUser.getId());
            if(bCryptPasswordEncoder.matches(sysUser.getOldPassword(),currentUser.getPassword())){
                currentUser.setPassword(bCryptPasswordEncoder.encode(sysUser.getNewPassword()));
                currentUser.setUpdateTime(new Date());
                sysUserService.updateById(currentUser);
                return new ResponseData("操作成功",200);
            }else{
                return new ResponseData("输入原密码错误!",500);
            }
        }
    }

头像更换功能的实现

参考官网的示例去实现
https://element-plus.gitee.io/zh-CN/component/upload.html#%E7%94%A8%E6%88%B7%E5%A4%B4%E5%83%8F

在这里插入图片描述

编写avatar.vue的组件代码:

需要注意的点:

1、:headers="headers"需要在请求的时候携带好token值
2、:action="getServerUrl()+‘sys/user/uploadImage’"后端的请求资源路径
3、:on-success="handleAvatarSuccess"成功的回调函数
4、:before-upload="beforeAvatarUpload"上传之前的回调函数

代码如下:
<template>
    <el-form
        ref="formRef"
        :model="form"
        label-width="100px"
        style="text-align: center;padding-bottom:10px"
    >
      <el-upload
          :headers="headers"
          class="avatar-uploader"
          :action="getServerUrl()+'sys/user/uploadImage'"
          :show-file-list="false"
          :on-success="handleAvatarSuccess"
          :before-upload="beforeAvatarUpload"
      >
        <img v-if="imageUrl" :src="imageUrl" class="avatar" />
        <el-icon v-else class="avatar-uploader-icon"><Plus /></el-icon>
      </el-upload>

      <el-button @click="handleConfirm" >确认更换</el-button>

    </el-form>


</template>

<script setup>

import {defineProps, ref} from "vue";
import requestUtil,{getServerUrl} from "@/util/request";
import { ElMessage } from 'element-plus'
import { Plus } from '@element-plus/icons-vue'
import store from "@/store";



const props=defineProps(
    {
      user:{
        type:Object,
        default:()=>{},
        required:true
      }
    }
)

const headers=ref({
  token:store.getters.GET_TOKEN
})

const form=ref({
  id:-1,
  avatar:''
})

const formRef=ref(null)

const imageUrl=ref("")

form.value=props.user;
imageUrl.value=getServerUrl()+'image/userAvatar/'+form.value.avatar

const handleAvatarSuccess=(res)=>{
  imageUrl.value=getServerUrl()+res.data.src
  form.value.avatar=res.data.title;
}


const beforeAvatarUpload = (file) => {
  const isJPG = file.type === 'image/jpeg'
  const isLt2M = file.size / 1024 / 1024 < 2

  if (!isJPG) {
    ElMessage.error('图片必须是jpg格式')
  }
  if (!isLt2M) {
    ElMessage.error('图片大小不能超过2M!')
  }
  return isJPG && isLt2M
}

  const handleConfirm=async()=>{

          let result=await requestUtil.post("sys/user/updateAvatar",form.value);
          let data=result.data;
          if(data.code==200){
            ElMessage.success("执行成功!")
            store.commit("SET_USERINFO",form.value)
          }else{
            ElMessage.error(data.msg);
          }

  }

</script>

<style>

.avatar-uploader .el-upload {
  border: 1px dashed #d9d9d9;
  border-radius: 6px;
  cursor: pointer;
  position: relative;
  overflow: hidden;
}
.avatar-uploader .el-upload:hover {
  border-color: #409eff;
}
.el-icon.avatar-uploader-icon {
  font-size: 28px;
  color: #8c939d;
  width: 178px;
  height: 178px;
  text-align: center;
}
.avatar {
  width: 120px;
  height: 120px;
  display: block;
}



</style>

预览效果:

在这里插入图片描述#### 后端的代码实现

为了防止传输文件名重复【使用时间格式化或者uuid之类的处理】
package com.xuguoguo.utils;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 日期工具类
 * @author xuguoguo
 *
 */
public class DateUtil {

    /**
     * 日期对象转字符串
     * @param date
     * @param format
     * @return
     */
    public static String formatDate(Date date,String format){
       String result="";
       SimpleDateFormat sdf=new SimpleDateFormat(format);
       if(date!=null){
          result=sdf.format(date);
       }
       return result;
    }
    
    /**
     * 字符串转日期对象
     * @param str
     * @param format
     * @return
     * @throws Exception
     */
    public static Date formatString(String str,String format) throws Exception{
       if(StringUtil.isEmpty(str)){
          return null;
       }
       SimpleDateFormat sdf=new SimpleDateFormat(format);
       return sdf.parse(str);
    }
    
    public static String getCurrentDateStr(){
       Date date=new Date();
       SimpleDateFormat sdf=new SimpleDateFormat("yyyyMMddhhmmssSSSSSSSSS");
       return sdf.format(date);
    }
    
    public static String getCurrentDatePath()throws Exception{
       Date date=new Date();
       SimpleDateFormat sdf=new SimpleDateFormat("yyyy/MM/dd/");
       return sdf.format(date);
    }
    
    public static void main(String[] args) {
       try {
          System.out.println(getCurrentDateStr());
       } catch (Exception e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
       }
    }
}

后端文件上传的请求方法
请求的文件上传的地址【修改yml进行动态的映射地址】

在这里插入图片描述

请求方法的编写

在这里插入图片描述

预览效果:
  • 未上传之前查看内容
    在这里插入图片描述- 选择头像弹出选择框进行选择头像
    在这里插入图片描述- 选择之后
    在这里插入图片描述- 查看存放文件的目录
    在这里插入图片描述
确认修改头像提交

在这里插入图片描述在这里插入图片描述

代码规整:
avatar.vue组件的内容如下:
<template>


    <el-form
        ref="formRef"
        :model="form"
        label-width="100px"
        style="text-align: center;padding-bottom:10px"
    >

      <el-upload
          :headers="headers"
          class="avatar-uploader"
          :action="getServerUrl()+'sys/user/uploadImage'"
          :show-file-list="false"
          :on-success="handleAvatarSuccess"
          :before-upload="beforeAvatarUpload"
      >
        <img v-if="imageUrl" :src="imageUrl" class="avatar" />
        <el-icon v-else class="avatar-uploader-icon"><Plus /></el-icon>
      </el-upload>

      <el-button @click="handleConfirm" >确认更换</el-button>

    </el-form>


</template>

<script setup>

import {defineProps, ref} from "vue";
import requestUtil,{getServerUrl} from "@/util/request";
import { ElMessage } from 'element-plus'
import { Plus } from '@element-plus/icons-vue'
import store from "@/store";



const props=defineProps(
    {
      user:{
        type:Object,
        default:()=>{},
        required:true
      }
    }
)

const headers=ref({
  token:store.getters.GET_TOKEN
})

const form=ref({
  id:-1,
  avatar:''
})

const formRef=ref(null)

const imageUrl=ref("")

form.value=props.user;
imageUrl.value=getServerUrl()+'image/userAvatar/'+form.value.avatar

const handleAvatarSuccess=(res)=>{
  imageUrl.value=getServerUrl()+res.data.src
  form.value.avatar=res.data.title;
}


const beforeAvatarUpload = (file) => {
  const isJPG = file.type === 'image/jpeg'
  const isLt2M = file.size / 1024 / 1024 < 2

  if (!isJPG) {
    ElMessage.error('图片必须是jpg格式')
  }
  if (!isLt2M) {
    ElMessage.error('图片大小不能超过2M!')
  }
  return isJPG && isLt2M
}

  const handleConfirm=async()=>{

          let result=await requestUtil.post("sys/user/updateAvatar",form.value);
          let data=result.data;
          if(data.code==200){
            ElMessage.success("执行成功!")
            store.commit("SET_USERINFO",form.value)
          }else{
            ElMessage.error(data.msg);
          }

  }

</script>

<style>

.avatar-uploader .el-upload {
  border: 1px dashed #d9d9d9;
  border-radius: 6px;
  cursor: pointer;
  position: relative;
  overflow: hidden;
}
.avatar-uploader .el-upload:hover {
  border-color: #409eff;
}
.el-icon.avatar-uploader-icon {
  font-size: 28px;
  color: #8c939d;
  width: 178px;
  height: 178px;
  text-align: center;
}
.avatar {
  width: 120px;
  height: 120px;
  display: block;
}



</style>

后端的请求处理:
@RestController
@RequestMapping("/sys/user")
public class SysUsersController {
    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    @Value("${avatarImagesFilePath}")
    private String avatarImagesFilePath;
    /**
     * 上传用户头像图片
     * @param file
     * @return
     * @throws Exception
     */
    @RequestMapping("/uploadImage")
    @PreAuthorize("hasAuthority('system:user:edit')")
    public Map<String,Object> uploadImage(MultipartFile file)throws Exception{
        Map<String,Object> resultMap=new HashMap<>();
        if(!file.isEmpty()){
            // 获取文件名
            String originalFilename = file.getOriginalFilename();
            String suffixName=originalFilename.substring(originalFilename.lastIndexOf("."));
            //防止重复的文件名[使用时间或者uuid之类的唯一值处理即可]
            String newFileName= DateUtil.getCurrentDateStr()+suffixName;
            FileUtils.copyInputStreamToFile(file.getInputStream(),new File(avatarImagesFilePath+newFileName));
            resultMap.put("code",0);
            resultMap.put("msg","上传成功");
            Map<String,Object> dataMap=new HashMap<>();
            dataMap.put("title",newFileName);
            dataMap.put("src","image/userAvatar/"+newFileName);
            resultMap.put("data",dataMap);
        }
        return resultMap;
    }



    /**
     * 修改用户头像
     * @param sysUser
     * @return
     */
    @RequestMapping("/updateAvatar")
    @PreAuthorize("hasAuthority('system:user:edit')")
    public ResponseData updateAvatar(@RequestBody SysUser sysUser){
        SysUser currentUser = sysUserService.getById(sysUser.getId());
        currentUser.setUpdateTime(new Date());
        currentUser.setAvatar(sysUser.getAvatar());
        sysUserService.updateById(currentUser);
        return new ResponseData("操作成功",200);
    }
}

小结

提示:本小结主体写的是个人中心、修改密码以及用户头像三个功能模块细化成前端的不同组件来实现的基本流程摘录,也是每个后台必有得功能哦!!!

本章的第八小节完毕,敬请期待后续更新(可留言需要学习哪方面的内容哈)!如果需要源码或者工具的朋友们可关注微信公众号"锅锅编程生活"或者扫描二维码关注回复关键字/后台留言获取即可!

在这里插入图片描述

  • 23
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值