[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"article-public-2Wkx3igg":3,"public-project-articles-2Wkx3igg":17},{"id":4,"uuid":5,"project_id":6,"title":7,"content":8,"type":9,"status":10,"public_enabled":10,"views":11,"sort":12,"created_at":13,"updated_at":14,"project_title":15,"project_slug":16},48,"2Wkx3igg",39,"15. Vue个人信息修改、修改密码、重置密码","\n## 个人中心\n\n注意：\n\u002F\u002F 触发父级的数据更新\nthis.$emit('update:user', this.user)\n\u003Crouter-view @update:user=\"updateUser\" \u002F>\n\n```\nupdateUser(user) {   \u002F\u002F 获取子组件传过来的数据  更新当前页面的数据\n  this.user = JSON.parse(JSON.stringify(user))  \u002F\u002F 让父级的对象跟子级的对象毫无关联\n},\n```\n\nPerson.vue\n\n```java\n\u003Ctemplate>\n  \u003Cdiv>\n    \u003Cel-card style=\"width: 50%\">\n      \u003Cel-form :model=\"user\" label-width=\"80px\" style=\"padding-right: 20px\">\n        \u003Cdiv style=\"margin: 15px; text-align: center\">\n          \u003Cel-upload\n              class=\"avatar-uploader\"\n              action=\"http:\u002F\u002Flocalhost:9090\u002Ffile\u002Fupload\"\n              :headers=\"{ token: user.token }\"\n              :show-file-list=\"false\"\n              :on-success=\"handleAvatarSuccess\"\n          >\n            \u003Cimg v-if=\"user.avatar\" :src=\"user.avatar\" class=\"avatar\" \u002F>\n            \u003Ci v-else class=\"el-icon-plus avatar-uploader-icon\">\u003C\u002Fi>\n          \u003C\u002Fel-upload>\n        \u003C\u002Fdiv>\n        \u003Cel-form-item label=\"用户名\" prop=\"username\">\n          \u003Cel-input v-model=\"user.username\" placeholder=\"用户名\" disabled>\u003C\u002Fel-input>\n        \u003C\u002Fel-form-item>\n        \u003Cel-form-item label=\"姓名\" prop=\"name\">\n          \u003Cel-input v-model=\"user.name\" placeholder=\"姓名\">\u003C\u002Fel-input>\n        \u003C\u002Fel-form-item>\n        \u003Cel-form-item label=\"电话\" prop=\"phone\">\n          \u003Cel-input v-model=\"user.phone\" placeholder=\"电话\">\u003C\u002Fel-input>\n        \u003C\u002Fel-form-item>\n        \u003Cel-form-item label=\"邮箱\" prop=\"email\">\n          \u003Cel-input v-model=\"user.email\" placeholder=\"邮箱\">\u003C\u002Fel-input>\n        \u003C\u002Fel-form-item>\n        \u003Cel-form-item label=\"地址\" prop=\"address\">\n          \u003Cel-input type=\"textarea\" v-model=\"user.address\" placeholder=\"地址\">\u003C\u002Fel-input>\n        \u003C\u002Fel-form-item>\n        \u003Cdiv style=\"text-align: center; margin-bottom: 20px\">\n          \u003Cel-button type=\"primary\" @click=\"update\">保 存\u003C\u002Fel-button>\n        \u003C\u002Fdiv>\n      \u003C\u002Fel-form>\n    \u003C\u002Fel-card>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\n\u003Cscript>\nexport default {\n  name: \"Person\",\n  data() {\n    return {\n      user: JSON.parse(localStorage.getItem('honey-user') || '{}')\n    }\n  },\n  created() {\n\n  },\n  methods: {\n    update() {\n      \u002F\u002F 保存当前的用户信息到数据库\n      this.$request.put('\u002Fuser\u002Fupdate', this.user).then(res => {\n        if (res.code === '200') {\n          \u002F\u002F 成功更新\n          this.$message.success('保存成功')\n\n          \u002F\u002F 更新浏览器缓存里的用户信息\n          localStorage.setItem('honey-user', JSON.stringify(this.user))\n\n          \u002F\u002F 触发父级的数据更新\n          this.$emit('update:user', this.user)\n        } else {\n          this.$message.error(res.msg)\n        }\n      })\n    },\n    handleAvatarSuccess(response, file, fileList) {\n      \u002F\u002F 把user的头像属性换成上传的图片的链接\n      this.user.avatar = response.data\n    },\n  }\n}\n\u003C\u002Fscript>\n\n\u003Cstyle scoped>\n\u002Fdeep\u002F.el-form-item__label {\n  font-weight: bold;\n}\n\u002Fdeep\u002F.el-upload {\n  border-radius: 50%;\n}\n\u002Fdeep\u002F.avatar-uploader .el-upload {\n  border: 1px dashed #d9d9d9;\n  cursor: pointer;\n  position: relative;\n  overflow: hidden;\n  border-radius: 50%;\n}\n\u002Fdeep\u002F.avatar-uploader .el-upload:hover {\n  border-color: #409EFF;\n}\n.avatar-uploader-icon {\n  font-size: 28px;\n  color: #8c939d;\n  width: 178px;\n  height: 178px;\n  line-height: 178px;\n  text-align: center;\n  border-radius: 50%;\n}\n.avatar {\n  width: 178px;\n  height: 178px;\n  display: block;\n  border-radius: 50%;\n}\n\u003C\u002Fstyle>\n```\n\n**错误： 重复点击当前路由的时候会出现这个错误**\n![image.png](https:\u002F\u002Fcdn.nlark.com\u002Fyuque\u002F0\u002F2023\u002Fpng\u002F751015\u002F1693488149376-b2c74b54-992c-493c-8381-d9610a626de8.png#averageHue=%23040508&clientId=u48759d36-5de4-4&from=paste&height=491&id=uf2292fb4&originHeight=614&originWidth=1675&originalType=binary&ratio=1.25&rotation=0&showTitle=false&size=159651&status=done&style=none&taskId=uf7b679d3-ec01-4978-9cad-18cddd7859a&title=&width=1340)\n在 router\u002Findex.js 里面加入下面的代码即可解决\n\n```javascript\n\u002F\u002F 解决导航栏或者底部导航tabBar中的vue-router在3.0版本以上频繁点击菜单报错的问题。\nconst originalPush = VueRouter.prototype.push\nVueRouter.prototype.push = function push (location) {\n  return originalPush.call(this, location).catch(err => err)\n}\n```\n\n## 修改密码\n\n```vue\n\u003Ctemplate>\n  \u003Cdiv>\n    \u003Cel-card style=\"width: 50%\">\n      \u003Cel-form ref=\"formRef\" :model=\"user\" :rules=\"rules\" label-width=\"80px\" style=\"padding-right: 20px\">\n        \u003Cel-form-item label=\"原始密码\" prop=\"password\">\n          \u003Cel-input show-password v-model=\"user.password\" placeholder=\"原始密码\">\u003C\u002Fel-input>\n        \u003C\u002Fel-form-item>\n        \u003Cel-form-item label=\"新密码\" prop=\"newPassword\">\n          \u003Cel-input show-password v-model=\"user.newPassword\" placeholder=\"新密码\">\u003C\u002Fel-input>\n        \u003C\u002Fel-form-item>\n        \u003Cel-form-item label=\"确认密码\" prop=\"confirmPassword\">\n          \u003Cel-input show-password v-model=\"user.confirmPassword\" placeholder=\"确认密码\">\u003C\u002Fel-input>\n        \u003C\u002Fel-form-item>\n        \u003Cdiv style=\"text-align: center; margin-bottom: 20px\">\n          \u003Cel-button type=\"primary\" @click=\"update\">确认修改\u003C\u002Fel-button>\n        \u003C\u002Fdiv>\n      \u003C\u002Fel-form>\n    \u003C\u002Fel-card>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\n\u003Cscript>\nexport default {\n  name: \"Password\",\n  data() {\n    const validatePassword = (rule, value, callback) => {\n      if (value === '') {\n        callback(new Error('请确认密码'))\n      } else if (value !== this.user.newPassword) {\n        callback(new Error('确认密码错误'))\n      } else {\n        callback()\n      }\n    }\n\n    return {\n      user: JSON.parse(localStorage.getItem('honey-user') || '{}'),\n      rules: {\n        password: [\n          { required: true, message: '请输入原始密码', trigger: 'blur' },\n        ],\n        newPassword: [\n          { required: true, message: '请输入新密码', trigger: 'blur' },\n        ],\n        confirmPassword: [\n          { validator: validatePassword, required: true, trigger: 'blur' },\n        ],\n      }\n    }\n  },\n  created() {\n\n  },\n  methods: {\n    update() {\n      this.$refs.formRef.validate((valid) => {\n        if (valid) {\n          this.user.password = this.user.newPassword\n          \u002F\u002F 保存当前的用户信息到数据库\n          this.$request.put('\u002Fuser\u002Fupdate', this.user).then(res => {\n            if (res.code === '200') {\n              \u002F\u002F 成功更新\n              this.$message.success('保存成功')\n              this.$router.push('\u002Flogin')\n            } else {\n              this.$message.error(res.msg)\n            }\n          })\n        }\n      })\n    },\n  }\n}\n\u003C\u002Fscript>\n\n\u003Cstyle scoped>\n\u002Fdeep\u002F.el-form-item__label {\n  font-weight: bold;\n}\n\u003C\u002Fstyle>\n```\n\n## 忘记密码\n\n前台\n\n```javascript\n\u003Cel-dialog title=\"忘记密码\" :visible.sync=\"forgetPassDialogVis\" width=\"30%\">\n      \u003Cel-form :model=\"forgetUserForm\" label-width=\"80px\" style=\"padding-right: 20px\">\n        \u003Cel-form-item label=\"用户名\">\n          \u003Cel-input v-model=\"forgetUserForm.username\" autocomplete=\"off\" placeholder=\"请输入用户名\">\u003C\u002Fel-input>\n        \u003C\u002Fel-form-item>\n        \u003Cel-form-item label=\"手机号\">\n          \u003Cel-input v-model=\"forgetUserForm.phone\" autocomplete=\"off\" placeholder=\"请输入手机号\">\u003C\u002Fel-input>\n        \u003C\u002Fel-form-item>\n      \u003C\u002Fel-form>\n      \u003Cdiv slot=\"footer\" class=\"dialog-footer\">\n        \u003Cel-button @click=\"forgetPassDialogVis = false\">取 消\u003C\u002Fel-button>\n        \u003Cel-button type=\"primary\" @click=\"resetPassword\">确 定\u003C\u002Fel-button>\n      \u003C\u002Fdiv>\n    \u003C\u002Fel-dialog>\n\ndata() {\n  return {\n     forgetUserForm: {},   \u002F\u002F 忘记密码的表单数据\n      forgetPassDialogVis: false,\n  }\n}\n\n\nhandleForgetPass() {   \u002F\u002F  初始化表单的数据\n  this.forgetUserForm = {}\n  this.forgetPassDialogVis = true\n},\nresetPassword() {\n  this.$request.put('\u002Fpassword', this.forgetUserForm).then(res => {\n    if (res.code === '200') {\n      this.$message.success('重置成功')\n      this.forgetPassDialogVis = false\n    } else {\n      this.$message.error(res.msg)\n    }\n  })\n},\n```\n\n后台\n\n```java\n\u002F**\n *  Controller重置密码\n *\u002F\n@AuthAccess\n@PutMapping(\"\u002Fpassword\")\npublic Result password(@RequestBody User user) {\n    if (StrUtil.isBlank(user.getUsername()) || StrUtil.isBlank(user.getPhone())) {\n        return Result.error(\"数据输入不合法\");\n    }\n    userService.resetPassword(user);\n    return Result.success();\n}\n\n\n\u002F\u002F  Service代码：\npublic void resetPassword(User user) {\n    User dbUser = userMapper.selectByUsername(user.getUsername());\n    if (dbUser == null) {\n        \u002F\u002F 抛出一个自定义的异常\n        throw new ServiceException(\"用户不存在\");\n    }\n    if (!user.getPhone().equals(dbUser.getPhone())) {\n        throw new ServiceException(\"验证错误\");\n    }\n    dbUser.setPassword(\"123\");   \u002F\u002F 重置密码\n    userMapper.updateUser(dbUser);\n}\n```\n\n小手一抖 就写错了，应该写 dbUser\n![image.png](https:\u002F\u002Fcdn.nlark.com\u002Fyuque\u002F0\u002F2023\u002Fpng\u002F751015\u002F1693490323854-40d5f5c8-4650-438b-ac22-3e1b75058075.png#averageHue=%232e2c2b&clientId=u510abc37-8577-4&from=paste&height=342&id=ue48d3757&originHeight=428&originWidth=941&originalType=binary&ratio=1.25&rotation=0&showTitle=false&size=43596&status=done&style=none&taskId=u4d9a7c4a-8432-4dd6-bd04-61e727bbf0b&title=&width=752.8)\n","coding",1,2092,70,"2024-04-16 02:32:33","2026-05-03 22:49:02","【青哥带小白做毕设2024】完整教程资料汇总","qingge-graduation-project-2024",{"project":18,"items":19},{"id":6,"title":15,"slug":16},[20,28,35,42,49,56,63,69,76,83,90,97,104,111,118,125,126,133,140,147,154,161,168],{"id":21,"uuid":22,"project_id":6,"title":23,"type":9,"status":10,"public_enabled":10,"views":24,"sort":25,"created_at":26,"updated_at":27,"project_title":15,"project_slug":16},33,"R1oMCsCX","00. 从0开始带小白做SpringBoot+Vue+uniapp微信小程序实战项目",12130,55,"2025-04-08 11:28:17","2026-05-07 15:33:28.189425+00",{"id":29,"uuid":30,"project_id":6,"title":31,"type":9,"status":10,"public_enabled":10,"views":32,"sort":33,"created_at":34,"updated_at":14,"project_title":15,"project_slug":16},34,"s3u3u8W7","01. 网页布局技巧",3326,56,"2025-04-08 11:28:13",{"id":36,"uuid":37,"project_id":6,"title":38,"type":9,"status":10,"public_enabled":10,"views":39,"sort":40,"created_at":41,"updated_at":14,"project_title":15,"project_slug":16},35,"21zUHQYS","02. JavaScript入门",2017,57,"2025-04-08 11:27:55",{"id":43,"uuid":44,"project_id":6,"title":45,"type":9,"status":10,"public_enabled":10,"views":46,"sort":47,"created_at":48,"updated_at":14,"project_title":15,"project_slug":16},36,"4XVgY9Ti","03. Vue脚手架搭建",3719,58,"2025-04-08 11:27:46",{"id":50,"uuid":51,"project_id":6,"title":52,"type":9,"status":10,"public_enabled":10,"views":53,"sort":54,"created_at":55,"updated_at":14,"project_title":15,"project_slug":16},37,"S8vLLLvk","04. Git速成，推送代码到云端",1585,59,"2025-04-08 11:27:41",{"id":57,"uuid":58,"project_id":6,"title":59,"type":9,"status":10,"public_enabled":10,"views":60,"sort":61,"created_at":62,"updated_at":14,"project_title":15,"project_slug":16},38,"9EbwnGDp","05. 网页布局神器ElementUI速成",2670,60,"2025-04-08 11:27:37",{"id":6,"uuid":64,"project_id":6,"title":65,"type":9,"status":10,"public_enabled":10,"views":66,"sort":67,"created_at":68,"updated_at":14,"project_title":15,"project_slug":16},"tmzahWer","06. Vue管理系统速成",3744,61,"2025-04-08 11:27:32",{"id":70,"uuid":71,"project_id":6,"title":72,"type":9,"status":10,"public_enabled":10,"views":73,"sort":74,"created_at":75,"updated_at":14,"project_title":15,"project_slug":16},40,"2agqAUQK","07. SpringBoot速成",3654,62,"2025-04-08 11:27:27",{"id":77,"uuid":78,"project_id":6,"title":79,"type":9,"status":10,"public_enabled":10,"views":80,"sort":81,"created_at":82,"updated_at":14,"project_title":15,"project_slug":16},41,"SXPAzgy7","08. Http扫盲，让小白也能听懂",2337,63,"2025-04-08 11:27:20",{"id":84,"uuid":85,"project_id":6,"title":86,"type":9,"status":10,"public_enabled":10,"views":87,"sort":88,"created_at":89,"updated_at":14,"project_title":15,"project_slug":16},42,"ostBIxAV","09. SpringBoot集成Mybatis实现增删改查",4190,64,"2025-04-08 11:27:13",{"id":91,"uuid":92,"project_id":6,"title":93,"type":9,"status":10,"public_enabled":10,"views":94,"sort":95,"created_at":96,"updated_at":14,"project_title":15,"project_slug":16},43,"6Sv7afpa","10. Vue封装前后端数据交互工具",3716,65,"2024-04-16 02:33:13",{"id":98,"uuid":99,"project_id":6,"title":100,"type":9,"status":10,"public_enabled":10,"views":101,"sort":102,"created_at":103,"updated_at":14,"project_title":15,"project_slug":16},44,"d53BPIQs","11. Vue登录（含验证码）、注册页面开发",4867,66,"2024-04-16 02:33:08",{"id":105,"uuid":106,"project_id":6,"title":107,"type":9,"status":10,"public_enabled":10,"views":108,"sort":109,"created_at":110,"updated_at":14,"project_title":15,"project_slug":16},45,"m033ng06","12. SpringBoot集成JWT token实现权限验证",3243,67,"2024-04-16 02:33:00",{"id":112,"uuid":113,"project_id":6,"title":114,"type":9,"status":10,"public_enabled":10,"views":115,"sort":116,"created_at":117,"updated_at":14,"project_title":15,"project_slug":16},46,"7xzyVD06","13. SpringBoot+Vue实现单文件、多文件上传和下载",2784,68,"2024-04-16 02:32:52",{"id":119,"uuid":120,"project_id":6,"title":121,"type":9,"status":10,"public_enabled":10,"views":122,"sort":123,"created_at":124,"updated_at":14,"project_title":15,"project_slug":16},47,"BdOLUenp","14. 多角色登录（Vue-Router路由守卫）",2318,69,"2024-04-16 02:32:39",{"id":4,"uuid":5,"project_id":6,"title":7,"type":9,"status":10,"public_enabled":10,"views":11,"sort":12,"created_at":13,"updated_at":14,"project_title":15,"project_slug":16},{"id":127,"uuid":128,"project_id":6,"title":129,"type":9,"status":10,"public_enabled":10,"views":130,"sort":131,"created_at":132,"updated_at":14,"project_title":15,"project_slug":16},49,"BDvVa4By","16. SpringBoot+Vue管理系统实现增删改查",2598,71,"2024-04-16 02:32:29",{"id":134,"uuid":135,"project_id":6,"title":136,"type":9,"status":10,"public_enabled":10,"views":137,"sort":138,"created_at":139,"updated_at":14,"project_title":15,"project_slug":16},50,"FJVl0rCu","17. SpringBoot+Vue实现数据的批量导入和导出",1684,72,"2024-04-16 02:32:26",{"id":141,"uuid":142,"project_id":6,"title":143,"type":9,"status":10,"public_enabled":10,"views":144,"sort":145,"created_at":146,"updated_at":14,"project_title":15,"project_slug":16},51,"FvW9oHgj","18. SpringBoot+Vue项目部署上线",2845,73,"2024-04-16 02:32:22",{"id":148,"uuid":149,"project_id":6,"title":150,"type":9,"status":10,"public_enabled":10,"views":151,"sort":152,"created_at":153,"updated_at":14,"project_title":15,"project_slug":16},52,"xyqrxxiR","19. SpringBoot+Vue集成富文本编辑器",1499,74,"2024-04-16 02:32:18",{"id":155,"uuid":156,"project_id":6,"title":157,"type":9,"status":10,"public_enabled":10,"views":158,"sort":159,"created_at":160,"updated_at":14,"project_title":15,"project_slug":16},53,"XAaCXz8W","20. SpringBoot+Vue集成系统公告",1043,75,"2024-04-16 02:32:14",{"id":162,"uuid":163,"project_id":6,"title":164,"type":9,"status":10,"public_enabled":10,"views":165,"sort":166,"created_at":167,"updated_at":14,"project_title":15,"project_slug":16},54,"2havlmaC","21. SpringBoot+Vue集成AOP系统日志",1159,76,"2024-04-16 02:32:11",{"id":25,"uuid":169,"project_id":6,"title":170,"type":9,"status":10,"public_enabled":10,"views":171,"sort":172,"created_at":173,"updated_at":14,"project_title":15,"project_slug":16},"ObvLqJdX","22. SpringBoot+Vue实现Echarts数据报表（柱状图、饼图、折线图）",1688,99,"2024-04-16 02:30:25"]