[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"article-public-1uMP9O6C":3,"public-project-articles-1uMP9O6C":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},776,"1uMP9O6C",49,"08. Springboot3+vue3实现登录注册功能","## 本节课效果图\n\n![](https:\u002F\u002Fcdn.nlark.com\u002Fyuque\u002F0\u002F2025\u002Fpng\u002F751015\u002F1740305445346-65cde58f-e12b-4723-95cc-f970bd28894f.png)\n\n## 素材\n\n![](https:\u002F\u002Fcdn.nlark.com\u002Fyuque\u002F0\u002F2025\u002Fjpeg\u002F751015\u002F1740300222797-2e100e78-f25a-42ef-a72b-33fce709bdf4.jpeg)![](https:\u002F\u002Fcdn.nlark.com\u002Fyuque\u002F0\u002F2025\u002Fjpeg\u002F751015\u002F1740300222888-9b314061-8a74-41c0-ae95-0891d55d49a0.jpeg)\n\n## 登录\n\n### 页面 Login.vue\n\n```vue\n\u003Ctemplate>\n  \u003Cdiv class=\"bg\">\n    \u003Cdiv style=\"width: 350px; background-color: #fff; border-radius: 5px; box-shadow: 0 0 10px rgba(0,0,0,0.1); padding: 40px 20px\">\n      \u003Cel-form ref=\"formRef\" :model=\"data.form\" :rules=\"data.rules\">\n        \u003Cdiv style=\"margin-bottom: 40px; text-align: center; font-weight: bold; font-size: 24px\">欢 迎 登 录\u003C\u002Fdiv>\n        \u003Cel-form-item prop=\"username\">\n          \u003Cel-input size=\"large\" v-model=\"data.form.username\" autocomplete=\"off\" prefix-icon=\"User\" placeholder=\"请输入账号\" \u002F>\n        \u003C\u002Fel-form-item>\n        \u003Cel-form-item prop=\"password\">\n          \u003Cel-input size=\"large\" show-password v-model=\"data.form.password\" autocomplete=\"off\" prefix-icon=\"Lock\" placeholder=\"请输入密码\" \u002F>\n        \u003C\u002Fel-form-item>\n        \u003Cel-form-item prop=\"role\">\n          \u003Cel-select size=\"large\" style=\"width: 100%\" v-model=\"data.form.role\">\n            \u003Cel-option label=\"管理员\" value=\"ADMIN\">\u003C\u002Fel-option>\n            \u003Cel-option label=\"普通用户\" value=\"USER\">\u003C\u002Fel-option>\n          \u003C\u002Fel-select>\n        \u003C\u002Fel-form-item>\n        \u003Cdiv style=\"margin-bottom: 20px\">\n          \u003Cel-button style=\"width: 100%\" size=\"large\" type=\"primary\" @click=\"login\">登 录\u003C\u002Fel-button>\n        \u003C\u002Fdiv>\n        \u003Cdiv style=\"text-align: right\">\n          还没有账号？请 \u003Ca style=\"color: #274afa\" href=\"\u002Fregister\">注册\u003C\u002Fa>\n        \u003C\u002Fdiv>\n      \u003C\u002Fel-form>\n    \u003C\u002Fdiv>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\n\u003Cscript setup>\nimport { reactive, ref } from \"vue\";\nimport request from \"@\u002Futils\u002Frequest.js\";\nimport {ElMessage} from \"element-plus\";\nimport router from \"@\u002Frouter\u002Findex.js\";\n\nconst formRef = ref()\nconst data = reactive({\n  form: { role: 'ADMIN' },\n  rules: {\n    username: [\n      { required: true, message: '请输入账号', trigger: 'blur' },\n      { min: 3, message: '账号最少3位', trigger: 'blur' },\n    ],\n    password: [\n      { required: true, message: '请输入密码', trigger: 'blur' }\n    ],\n  }\n})\n\nconst login = () => {\n  formRef.value.validate((valid) => {\n    if (valid) {\n      request.post('\u002Flogin', data.form).then(res => {\n        if (res.code === '200') {\n          \u002F\u002F 存储用户信息\n          localStorage.setItem(\"code_user\", JSON.stringify(res.data || {}))\n          ElMessage.success('登录成功')\n          router.push('\u002F')\n        } else {\n          ElMessage.error(res.msg)\n        }\n      })\n    }\n  })\n}\n\u003C\u002Fscript>\n\n\u003Cstyle scoped>\n.bg {\n  height: 100vh;\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  overflow: hidden;\n  background-image: url(\"@\u002Fassets\u002Fimgs\u002Fbg.jpg\");\n  background-size: cover;\n}\n\u003C\u002Fstyle>\n```\n\n存储用户信息\n\n![](https:\u002F\u002Fcdn.nlark.com\u002Fyuque\u002F0\u002F2025\u002Fpng\u002F751015\u002F1740301818062-c9e142f6-086e-4ae6-b147-d02ccde2d5dc.png)\n\n### 登录接口\n\ncontroller\n\n```java\n@PostMapping(\"\u002Flogin\")\npublic Result login(@RequestBody Account account) {\n    Account dbAccount = null;\n    if (\"ADMIN\".equals(account.getRole())) {\n        dbAccount = adminService.login(account);\n    } else if (\"USER\".equals(account.getRole())) {\n        dbAccount = userService.login(account);\n    } else {\n        throw new CustomerException(\"非法请求\");\n    }\n    return Result.success(dbAccount);\n}\n```\n\nservice\n\n```java\npublic Admin login(Account account) {\n    \u002F\u002F 验证账号是否存在\n    Admin dbAdmin = adminMapper.selectByUsername(account.getUsername());\n    if (dbAdmin == null) {\n        throw new CustomerException(\"账号不存在\");\n    }\n    \u002F\u002F 验证密码是否正确\n    if (!dbAdmin.getPassword().equals(account.getPassword())) {\n        throw new CustomerException(\"账号或密码错误\");\n    }\n    return dbAdmin;\n}\n```\n\n## 模仿管理员开发用户管理\n\n### 数据库表 user\n\n```sql\nCREATE TABLE `user` (\n  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',\n  `username` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '账号',\n  `password` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '密码',\n  `name` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '名称',\n  `phone` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '手机',\n  `email` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '邮箱',\n  `role` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '角色',\n  PRIMARY KEY (`id`),\n  UNIQUE KEY `username_index` (`username`) COMMENT '账号'\n) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='管理员信息';\n```\n\n### User 相关的接口 和 管理页面\n\n开发的过程：复制 Admin 相关的 Entity、Controller、Service、Mapper、Mapper,xml ，然后改名\n\nAdmin - > User 即可 \n\n\n\n**注意 UserService 的 add 方法  和 AdminService 的 add 方法 的区别**\n\nuser\n\n```java\npublic void add(User user) {\n    \u002F\u002F 根据新的账号查询数据库  是否存在同样账号的数据\n    User dbUser = userMapper.selectByUsername(user.getUsername());\n    if (dbUser != null) {\n        throw new CustomerException(\"账号重复\");\n    }\n    \u002F\u002F 默认密码\n    if (StrUtil.isBlank(user.getPassword())) {\n        user.setPassword(\"123\");\n    }\n    if (StrUtil.isBlank(user.getName())) {\n        user.setName(user.getUsername());\n    }\n    user.setRole(\"USER\");\n    userMapper.insert(user);\n}\n\n```\n\n\n\nadmin\n\n```java\npublic void add(Admin admin) {\n    \u002F\u002F 根据新的账号查询数据库  是否存在同样账号的数据\n    Admin dbAdmin = adminMapper.selectByUsername(admin.getUsername());\n    if (dbAdmin != null) {\n        throw new CustomerException(\"账号重复\");\n    }\n    \u002F\u002F 默认密码\n    if (StrUtil.isBlank(admin.getPassword())) {\n        admin.setPassword(\"admin\");\n    }\n    admin.setRole(\"ADMIN\");\n    adminMapper.insert(admin);\n}\n```\n\n\n\n### 注意在  AdminMapper.xml 和 UserMapper.xml 里面补充 role\n\n![](https:\u002F\u002Fcdn.nlark.com\u002Fyuque\u002F0\u002F2025\u002Fpng\u002F751015\u002F1740304877132-e5145f9a-dd79-442c-b968-1c7b330c7eec.png)\n\n### 遇到  ”未找到接口“的问题\n\n这是因为没有重启后台，重启即可\n\n## 注册\n\n### 页面 Register.vue\n\n按钮颜色：#248243\n\n```vue\n\u003Ctemplate>\n  \u003Cdiv class=\"bg\">\n    \u003Cdiv style=\"width: 350px; background-color: #fff; border-radius: 5px; box-shadow: 0 0 10px rgba(0,0,0,0.1); padding: 40px 20px\">\n      \u003Cel-form status-icon ref=\"formRef\" :model=\"data.form\" :rules=\"data.rules\">\n        \u003Cdiv style=\"margin-bottom: 40px; text-align: center; font-weight: bold; font-size: 24px\">欢 迎 注 册\u003C\u002Fdiv>\n        \u003Cel-form-item prop=\"username\">\n          \u003Cel-input size=\"large\" v-model=\"data.form.username\" autocomplete=\"off\" prefix-icon=\"User\" placeholder=\"请输入账号\" \u002F>\n        \u003C\u002Fel-form-item>\n        \u003Cel-form-item prop=\"password\">\n          \u003Cel-input size=\"large\" show-password v-model=\"data.form.password\" autocomplete=\"off\" prefix-icon=\"Lock\" placeholder=\"请输入密码\" \u002F>\n        \u003C\u002Fel-form-item>\n        \u003Cel-form-item prop=\"confirmPassword\">\n          \u003Cel-input size=\"large\" show-password v-model=\"data.form.confirmPassword\" autocomplete=\"off\" prefix-icon=\"Lock\" placeholder=\"请再次确认密码\" \u002F>\n        \u003C\u002Fel-form-item>\n        \u003Cdiv style=\"margin-bottom: 20px\">\n          \u003Cel-button style=\"width: 100%; background-color: #248243; border-color: #248243\" size=\"large\" type=\"primary\" @click=\"register\">注 册\u003C\u002Fel-button>\n        \u003C\u002Fdiv>\n        \u003Cdiv style=\"text-align: right\">\n          已有账号？请 \u003Ca style=\"color: #248243\" href=\"\u002Flogin\">登录\u003C\u002Fa>\n        \u003C\u002Fdiv>\n      \u003C\u002Fel-form>\n    \u003C\u002Fdiv>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\n\u003Cscript setup>\nimport { reactive, ref } from \"vue\";\nimport request from \"@\u002Futils\u002Frequest.js\";\nimport {ElMessage} from \"element-plus\";\nimport router from \"@\u002Frouter\u002Findex.js\";\n\nconst validatePass = (rule, value, callback) => {\n  \u002F\u002F value 表示用户输入的确认密码\n  if (value !== data.form.password) {\n    callback(new Error(\"两次输入的密码不匹配！\"))\n  } else {\n    callback()\n  }\n}\n\nconst formRef = ref()\nconst data = reactive({\n  form: {},\n  rules: {\n    username: [\n      { required: true, message: '请输入账号', trigger: 'blur' },\n      { min: 3, message: '账号最少3位', trigger: 'blur' },\n    ],\n    password: [\n      { required: true, message: '请输入密码', trigger: 'blur' }\n    ],\n    confirmPassword: [\n      { required: true, message: '请再次确认密码', trigger: 'blur' },\n      { validator: validatePass, trigger: 'blur' }\n    ]\n  }\n})\n\nconst register = () => {\n  formRef.value.validate((valid) => {\n    if (valid) {\n      request.post('\u002Fregister', data.form).then(res => {\n        if (res.code === '200') {\n          ElMessage.success('注册成功')\n          router.push('\u002Flogin')\n        } else {\n          ElMessage.error(res.msg)\n        }\n      })\n    }\n  })\n}\n\u003C\u002Fscript>\n\n\u003Cstyle scoped>\n.bg {\n  height: 100vh;\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  overflow: hidden;\n  background-image: url(\"@\u002Fassets\u002Fimgs\u002Fbg1.jpg\");\n  background-size: cover;\n}\n\u003C\u002Fstyle>\n```\n\n### 注册接口\n\ncontroller\n\n```java\n@PostMapping(\"\u002Fregister\")\npublic Result register(@RequestBody User user) {\n    userService.register(user);\n    return Result.success();\n}\n```\n\nservice\n\n```java\npublic void register(User user) {\n    this.add(user);\n}\n```\n\n### 自定义的错误\n\n不是系统的错误，不是代码的 bug，这是我们给前端抛出的错误信息\n\n### 当你看到页面一片空白怎么办？\n\n打开页面的控制台，看看具体的报错信息，然后解决问题\n\n\n\n## 本节课代码 样例\n\nManager.vue\n\n```vue\n\u003Ctemplate>\n  \u003Cdiv>\n    \u003C!-- 头部区域开始 -->\n    \u003Cdiv style=\"height: 60px; display: flex;\">\n      \u003Cdiv style=\"width: 240px; display: flex; align-items: center; padding-left: 20px; background-color: #3a456b\">\n        \u003Cimg style=\"width: 40px; height: 40px; border-radius: 50%\" src=\"@\u002Fassets\u002Fimgs\u002Flogo.png\" alt=\"\">\n        \u003Cspan style=\"font-size: 20px; font-weight: bold; color: #f1f1f1; margin-left: 5px\">小白做毕设2025\u003C\u002Fspan>\n      \u003C\u002Fdiv>\n      \u003Cdiv style=\"flex: 1; display: flex; align-items: center; padding-left: 20px; border-bottom: 1px solid #ddd\">\n        \u003Cspan style=\"margin-right: 5px; cursor: pointer\" @click=\"router.push('\u002Fmanager\u002Fhome')\">首页\u003C\u002Fspan> \u002F \u003Cspan style=\"margin-left: 5px\">{{ router.currentRoute.value.meta.name }}\u003C\u002Fspan>\n      \u003C\u002Fdiv>\n      \u003Cdiv style=\"width: fit-content; padding-right: 20px; display: flex; align-items: center; border-bottom: 1px solid #ddd\">\n        \u003Cel-dropdown>\n          \u003Cdiv style=\"display: flex; align-items: center\">\n            \u003Cimg style=\"width: 40px; height: 40px; border-radius: 50%\" src=\"https:\u002F\u002Fcube.elemecdn.com\u002F3\u002F7c\u002F3ea6beec64369c2642b92c6726f1epng.png\" alt=\"\">\n            \u003Cspan style=\"margin-left: 5px\">{{ data.user?.name }}\u003C\u002Fspan>\n          \u003C\u002Fdiv>\n          \u003Ctemplate #dropdown>\n            \u003Cel-dropdown-menu>\n              \u003Cel-dropdown-item>个人信息\u003C\u002Fel-dropdown-item>\n              \u003Cel-dropdown-item>修改密码\u003C\u002Fel-dropdown-item>\n              \u003Cel-dropdown-item @click=\"logout\">退出登录\u003C\u002Fel-dropdown-item>\n            \u003C\u002Fel-dropdown-menu>\n          \u003C\u002Ftemplate>\n        \u003C\u002Fel-dropdown>\n      \u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n    \u003C!--  头部区域结束 -->\n\n    \u003C!--  下方区域开始 -->\n    \u003Cdiv style=\"display: flex\">\n      \u003C!--  菜单区域开始 -->\n      \u003Cdiv style=\"width: 240px;\">\n        \u003Cel-menu router :default-openeds=\"['1']\" :default-active=\"router.currentRoute.value.path\" style=\"min-height: calc(100vh - 60px)\">\n          \u003Cel-menu-item index=\"\u002Fmanager\u002Fhome\">\n            \u003Cel-icon>\u003CHouse \u002F>\u003C\u002Fel-icon>\n            \u003Cspan>首页\u003C\u002Fspan>\n          \u003C\u002Fel-menu-item>\n          \u003Cel-sub-menu index=\"1\">\n            \u003Ctemplate #title>\n              \u003Cel-icon>\u003Clocation \u002F>\u003C\u002Fel-icon>\n              \u003Cspan>用户管理\u003C\u002Fspan>\n            \u003C\u002Ftemplate>\n            \u003Cel-menu-item index=\"\u002Fmanager\u002Fadmin\">管理员信息\u003C\u002Fel-menu-item>\n            \u003Cel-menu-item index=\"\u002Fmanager\u002Fuser\">普通用户信息\u003C\u002Fel-menu-item>\n          \u003C\u002Fel-sub-menu>\n        \u003C\u002Fel-menu>\n      \u003C\u002Fdiv>\n      \u003C!--  菜单区域结束 -->\n\n      \u003C!--  数据渲染区域开始 -->\n      \u003Cdiv style=\"flex: 1; width: 0; padding: 10px; background-color: #f2f4ff\">\n        \u003CRouterView \u002F>\n      \u003C\u002Fdiv>\n      \u003C!--  数据渲染区域结束 -->\n\n    \u003C\u002Fdiv>\n    \u003C!--  下方区域结束 -->\n\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\n\u003Cscript setup>\nimport router from \"@\u002Frouter\u002Findex.js\";\nimport { reactive } from \"vue\";\n\nconst data = reactive({\n  user: JSON.parse(localStorage.getItem('code_user') || \"{}\")\n})\n\nconst logout = () => {\n  localStorage.removeItem('code_user')\n  location.href = '\u002Flogin'\n}\n\nif (!data.user?.id) {\n  location.href = '\u002Flogin'\n}\n\u003C\u002Fscript>\n\n\u003Cstyle>\n.el-menu {\n  background-color: #3a456b;\n  border: none;\n}\n.el-sub-menu__title {\n  background-color: #3a456b;\n  color: #ddd;\n}\n.el-menu-item {\n  height: 50px;\n  color: #ddd;\n}\n.el-menu .is-active {\n  background-color: #537bee;\n  color: #fff;\n}\n.el-sub-menu__title:hover {\n  background-color: #3a456b;\n}\n.el-menu-item:not(.is-active):hover {\n  background-color: #7a9fff;\n  color: #333;\n}\n.el-dropdown {\n  cursor: pointer;\n}\n.el-tooltip__trigger {\n  outline: none;\n}\n.el-menu--inline .el-menu-item {\n  padding-left: 48px !important;\n}\n\u003C\u002Fstyle>\n```\n\n","coding",1,7964,1522,"2025-02-23 18:14:13","2026-05-03 22:49:02","带小白做毕设2025系列课程","graduation-project-2025",{"project":18,"items":19},{"id":6,"title":15,"slug":16},[20,28,35,42,49,56,63,70,77,78,85,92,99,106,113,120,127,134,141,148,155],{"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},766,"XmlcAcY0","00. 带小白做毕设2025课程介绍",19012,1512,"2025-02-22 15:29:01","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},767,"nmjXCdVH","01. 前端Vue3 框架的快速搭建以及项目工程的讲解",15797,1513,"2025-02-13 17:13:40",{"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},768,"pMdPrVeH","02. 使用Vue3集成Element-Plus快速搭建一个管理系统的页面框架",15959,1514,"2025-02-14 11:25:07",{"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},771,"8PikYMQU","03. Springboot3框架的快速搭建以及项目工程的讲解",12768,1517,"2025-02-21 17:21:51",{"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},772,"Q1TCG9Jj","04. Springboot3整合MyBatis实现数据库操作",11144,1518,"2025-03-07 15:50:30",{"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},773,"De7YPnEc","05. Springboot3+vue3实现增删改查、分页查询、批量删除（上）",10827,1519,"2025-02-22 15:09:19",{"id":64,"uuid":65,"project_id":6,"title":66,"type":9,"status":10,"public_enabled":10,"views":67,"sort":68,"created_at":69,"updated_at":14,"project_title":15,"project_slug":16},774,"YKEHfsPd","06. Springboot3+vue3实现增删改查、分页查询、批量删除（下）",7760,1520,"2025-02-22 22:00:02",{"id":71,"uuid":72,"project_id":6,"title":73,"type":9,"status":10,"public_enabled":10,"views":74,"sort":75,"created_at":76,"updated_at":14,"project_title":15,"project_slug":16},775,"sNDKpWVJ","07. Springboot3+Vue3实现excel批量导入导出",6552,1521,"2025-02-23 10:49:24",{"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":79,"uuid":80,"project_id":6,"title":81,"type":9,"status":10,"public_enabled":10,"views":82,"sort":83,"created_at":84,"updated_at":14,"project_title":15,"project_slug":16},777,"WahvQp1v","09. Springboot3+vue3实现JWT登录鉴权",7151,1523,"2025-02-23 21:58:00",{"id":86,"uuid":87,"project_id":6,"title":88,"type":9,"status":10,"public_enabled":10,"views":89,"sort":90,"created_at":91,"updated_at":14,"project_title":15,"project_slug":16},778,"QFFAqZh1","10. Springboot3+vue3实现文件上传和下载",6171,1524,"2025-02-24 14:16:27",{"id":93,"uuid":94,"project_id":6,"title":95,"type":9,"status":10,"public_enabled":10,"views":96,"sort":97,"created_at":98,"updated_at":14,"project_title":15,"project_slug":16},1278,"S2eL2g5L","11. Springboot3+vue3实现个人中心、修改密码",5945,1525,"2025-02-24 18:10:59",{"id":100,"uuid":101,"project_id":6,"title":102,"type":9,"status":10,"public_enabled":10,"views":103,"sort":104,"created_at":105,"updated_at":14,"project_title":15,"project_slug":16},1279,"LkN8Mmsn","12. Springboot3+Vue3实现系统公告功能",4967,1526,"2025-02-25 11:50:13",{"id":107,"uuid":108,"project_id":6,"title":109,"type":9,"status":10,"public_enabled":10,"views":110,"sort":111,"created_at":112,"updated_at":14,"project_title":15,"project_slug":16},1280,"i7wziuEN","13. Springboot3+Vue3实现角色权限控制",4446,1527,"2025-02-25 11:51:38",{"id":114,"uuid":115,"project_id":6,"title":116,"type":9,"status":10,"public_enabled":10,"views":117,"sort":118,"created_at":119,"updated_at":14,"project_title":15,"project_slug":16},1281,"pGwiTCRn","14. Springboot3+Vue3实现富文本编辑器功能",4578,1528,"2025-02-26 16:04:58",{"id":121,"uuid":122,"project_id":6,"title":123,"type":9,"status":10,"public_enabled":10,"views":124,"sort":125,"created_at":126,"updated_at":14,"project_title":15,"project_slug":16},1282,"tZ8iDql5","15. Springboot3+Vue3实现模块之间的关联",4454,1529,"2025-02-26 18:28:55",{"id":128,"uuid":129,"project_id":6,"title":130,"type":9,"status":10,"public_enabled":10,"views":131,"sort":132,"created_at":133,"updated_at":14,"project_title":15,"project_slug":16},1283,"gb01JPC2","16. Springboot3+Vue3实现echarts数据统计",4307,1530,"2025-03-03 16:58:21",{"id":135,"uuid":136,"project_id":6,"title":137,"type":9,"status":10,"public_enabled":10,"views":138,"sort":139,"created_at":140,"updated_at":14,"project_title":15,"project_slug":16},1284,"59bDkSFf","17. Springboot3+Vue3实现提交审核业务功能",3793,1531,"2025-03-04 11:58:16",{"id":142,"uuid":143,"project_id":6,"title":144,"type":9,"status":10,"public_enabled":10,"views":145,"sort":146,"created_at":147,"updated_at":14,"project_title":15,"project_slug":16},1285,"gApyb58X","18. Springboot3+Vue3实现预约审核业务功能",3332,1532,"2025-03-05 20:07:24",{"id":149,"uuid":150,"project_id":6,"title":151,"type":9,"status":10,"public_enabled":10,"views":152,"sort":153,"created_at":154,"updated_at":14,"project_title":15,"project_slug":16},1286,"XfpY5re0","19. Springboot3+Vue3实现前台首页的设计",3508,1533,"2025-03-05 20:08:12",{"id":156,"uuid":157,"project_id":6,"title":158,"type":9,"status":10,"public_enabled":10,"views":159,"sort":160,"created_at":161,"updated_at":14,"project_title":15,"project_slug":16},1287,"BnSPRBOc","20. Springboot3+Vue3实现前台轮播图和详情页的设计",4062,1534,"2025-03-17 17:13:36"]