[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"article-public-qKG13ySo":3,"public-project-articles-qKG13ySo":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},519,"qKG13ySo",47,"10. SpringBoot3+Vue3实现基本的增删改查功能","## 本节课要求\n\n先学完本节课的内容，然后不看视频和笔记，自己能独立完成下面的这个页面的基本的**增删改查**\n\n只有完成这个功能，你才能跟后面的课程\n\n![](https:\u002F\u002Fcdn.nlark.com\u002Fyuque\u002F0\u002F2024\u002Fpng\u002F751015\u002F1729239990544-d5187cea-64c0-43e8-817e-c58a1ff8987d.png)\n\n## 安装 axios 封装前后端对接数据工具\n\n```vue\nnpm i axios -S\n```\n\nrequest.js\n\n```javascript\nimport axios from \"axios\";\nimport {ElMessage} from \"element-plus\";\n\nconst request = axios.create({\n  baseURL: 'http:\u002F\u002Flocalhost:9090',\n  timeout: 30000  \u002F\u002F 后台接口超时时间\n})\n\n\u002F\u002F request 拦截器\n\u002F\u002F 可以自请求发送前对请求做一些处理\nrequest.interceptors.request.use(config => {\n  config.headers['Content-Type'] = 'application\u002Fjson;charset=utf-8';\n  return config\n}, error => {\n  return Promise.reject(error)\n});\n\n\u002F\u002F response 拦截器\n\u002F\u002F 可以在接口响应后统一处理结果\nrequest.interceptors.response.use(\n  response => {\n    let res = response.data;\n    \u002F\u002F 兼容服务端返回的字符串数据\n    if (typeof res === 'string') {\n      res = res ? JSON.parse(res) : res\n    }\n    return res;\n  },\n  error => {\n    if (error.response.status === 404) {\n      ElMessage.error('未找到请求接口')\n    } else if (error.response.status === 500) {\n      ElMessage.error('系统异常，请查看后端控制台报错')\n    } else {\n      console.error(error.message)\n    }\n    return Promise.reject(error)\n  }\n)\n\nexport default request\n```\n\n## 一个最简单的请求示例\n\n```vue\nimport request from \"@\u002Futils\u002Frequest.js\";\n```\n\n```vue\nrequest.get('\u002Femployee\u002FselectAll').then(res => {\n  console.log(res)  \u002F\u002F 打印数据\n  data.employeeList = res.data   \u002F\u002F  res.data就是员工的列表数据  是一个数组\n  console.log(data.employeeList)\n})\n```\n\n## 遇到了跨域错误\n\n![](https:\u002F\u002Fcdn.nlark.com\u002Fyuque\u002F0\u002F2024\u002Fpng\u002F751015\u002F1729234877148-f2cdfffd-4d59-4dc0-bf7e-3fec8e10a4be.png)\n\n在 Springboot 里面设置统一的跨域处理\n\n```java\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.web.cors.CorsConfiguration;\nimport org.springframework.web.cors.UrlBasedCorsConfigurationSource;\nimport org.springframework.web.filter.CorsFilter;\n\n\u002F**\n * 跨域配置\n *\u002F\n@Configuration\npublic class CorsConfig {\n\n    @Bean\n    public CorsFilter corsFilter() {\n        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();\n        CorsConfiguration corsConfiguration = new CorsConfiguration();\n        corsConfiguration.addAllowedOrigin(\"*\"); \u002F\u002F 1 设置访问源地址\n        corsConfiguration.addAllowedHeader(\"*\"); \u002F\u002F 2 设置访问源请求头\n        corsConfiguration.addAllowedMethod(\"*\"); \u002F\u002F 3 设置访问源请求方法\n        source.registerCorsConfiguration(\"\u002F**\", corsConfiguration); \u002F\u002F 4 对接口配置跨域设置\n        return new CorsFilter(source);\n    }\n}\n```\n\n设置完后记得重启\n\n## 🔴学会分析网络请求\u003Cfont style=\"color:#DF2A3F;\">（以后排查问题的关键手段）\u003C\u002Ffont>\n\n![](https:\u002F\u002Fcdn.nlark.com\u002Fyuque\u002F0\u002F2024\u002Fpng\u002F751015\u002F1729235249578-f06f543e-475e-4e41-8a95-a8ed5ab7d58f.png)\n\n![](https:\u002F\u002Fcdn.nlark.com\u002Fyuque\u002F0\u002F2024\u002Fpng\u002F751015\u002F1729235293276-a7ace8a2-73da-474e-b2c5-e9b0b266b473.png)\n\n## 分页查询数据\n\n![](https:\u002F\u002Fcdn.nlark.com\u002Fyuque\u002F0\u002F2024\u002Fpng\u002F751015\u002F1729235919744-d90598e4-294b-4ba1-8c66-05da7866a1e6.png)\n\n当你发起请求的时候携带了参数，你可以在 **载荷 **这里查看\n\ntable\n\n```vue\n\u003Cel-table :data=\"data.tableData\" stripe>\n  \u003Cel-table-column label=\"名称\" prop=\"name\" \u002F>\n  \u003Cel-table-column label=\"性别\" prop=\"sex\" \u002F>\n  \u003Cel-table-column label=\"工号\" prop=\"no\" \u002F>\n  \u003Cel-table-column label=\"年龄\" prop=\"age\" \u002F>\n  \u003Cel-table-column label=\"个人介绍\" prop=\"description\" show-overflow-tooltip \u002F>\n  \u003Cel-table-column label=\"部门\" prop=\"departmentName\" \u002F>\n\u003C\u002Fel-table>\n\u003Cdiv style=\"margin-top: 15px\">\n  \u003Cel-pagination\n      @size-change=\"load\"\n      @current-change=\"load\"\n      v-model:current-page=\"data.pageNum\"\n      v-model:page-size=\"data.pageSize\"\n      :page-sizes=\"[5, 10, 15, 20]\"\n      background\n      layout=\"total, sizes, prev, pager, next, jumper\"\n      :total=\"data.total\"\n  \u002F>\n\u003C\u002Fdiv>\n```\n\n请求数据\n\n```vue\n\u003Cscript setup>\nimport { reactive } from \"vue\";\nimport { Search } from \"@element-plus\u002Ficons-vue\"\nimport request from \"@\u002Futils\u002Frequest.js\";\n\nconst data = reactive({\n  name: null,\n  tableData: [],\n  pageNum: 1,\n  pageSize: 10,\n  total: 0\n})\n\nconst load = () => {\n  request.get('\u002Femployee\u002FselectPage', { \u002F\u002F ?pageNum=1&pageSize=10\n    params: {\n      pageNum: data.pageNum,\n      pageSize: data.pageSize\n    }\n  }).then(res => {\n    data.tableData = res.data.list\n    data.total = res.data.total\n  })\n}\nload()\n\u003C\u002Fscript>\n```\n\n## 条件查询\n\n### 动态条件查询\n\n![](https:\u002F\u002Fcdn.nlark.com\u002Fyuque\u002F0\u002F2024\u002Fpng\u002F751015\u002F1729236629008-e43b5075-2000-4d2c-b47a-81a0e25ee68a.png)\n\n查询 sql\n\n![](https:\u002F\u002Fcdn.nlark.com\u002Fyuque\u002F0\u002F2024\u002Fpng\u002F751015\u002F1729236754970-5f32827e-2c9a-4b96-8b9c-6535bb4649ca.png)\n\n## 新增数据\n\n1. 新增弹窗组件 设置表单\n\n```vue\n\u003Cel-dialog title=\"员工信息\" v-model=\"data.formVisible\" width=\"500\">\n  \u003Cel-form :model=\"data.form\" label-width=\"80px\" style=\"padding-right: 40px; padding-top: 20px\">\n    \u003Cel-form-item label=\"名称\">\n      \u003Cel-input v-model=\"data.form.name\" autocomplete=\"off\" placeholder=\"请输入名称\" \u002F>\n    \u003C\u002Fel-form-item>\n    \u003Cel-form-item label=\"性别\">\n      \u003Cel-radio-group v-model=\"data.form.sex\">\n        \u003Cel-radio value=\"男\" label=\"男\">\u003C\u002Fel-radio>\n        \u003Cel-radio value=\"女\" label=\"女\">\u003C\u002Fel-radio>\n      \u003C\u002Fel-radio-group>\n    \u003C\u002Fel-form-item>\n    \u003Cel-form-item label=\"工号\">\n      \u003Cel-input v-model=\"data.form.no\" autocomplete=\"off\"  placeholder=\"请输入工号\" \u002F>\n    \u003C\u002Fel-form-item>\n    \u003Cel-form-item label=\"年龄\">\n      \u003Cel-input-number style=\"width: 180px\" :min=\"18\" v-model=\"data.form.age\" autocomplete=\"off\"  placeholder=\"请输入年龄\" \u002F>\n    \u003C\u002Fel-form-item>\n    \u003Cel-form-item label=\"个人介绍\">\n      \u003Cel-input :rows=\"3\" type=\"textarea\" v-model=\"data.form.description\" autocomplete=\"off\" placeholder=\"请输入个人介绍\" \u002F>\n    \u003C\u002Fel-form-item>\n  \u003C\u002Fel-form>\n  \u003Ctemplate #footer>\n    \u003Cdiv class=\"dialog-footer\">\n      \u003Cel-button @click=\"data.formVisible = false\">取 消\u003C\u002Fel-button>\n      \u003Cel-button type=\"primary\" @click=\"save\">保 存\u003C\u002Fel-button>\n    \u003C\u002Fdiv>\n  \u003C\u002Ftemplate>\n\u003C\u002Fel-dialog>\n```\n\n通过 handleAdd 打开弹窗\n\n```vue\nconst handleAdd = () => {\n  data.formVisible = true\n  data.form = {}\n  }\n```\n\n2.点击保存按钮 发起请求\n\n```vue\nconst save = () => {\n  request.post('\u002Femployee\u002Fadd', data.form).then(res => {\n  if (res.code === '200') {\n  data.formVisible = false\n  ElMessage.success('操作成功')\n  load()  \u002F\u002F 新增后一定要重新加载最新的数据\n  } else {\n  ElMessage.error(res.msg)\n  }\n  })\n  }\n```\n\n\n\n![](https:\u002F\u002Fcdn.nlark.com\u002Fyuque\u002F0\u002F2024\u002Fpng\u002F751015\u002F1729237765950-65490d07-54aa-462d-a499-26d1e473c5b3.png)\n\n![](https:\u002F\u002Fcdn.nlark.com\u002Fyuque\u002F0\u002F2024\u002Fpng\u002F751015\u002F1729237846969-ecd5ab54-6386-401f-8b82-9382a14cd7cc.png)\n\n## 编辑数据\n\n1. 打开弹窗\n2. 设置弹窗数据\n3. 调用更新的接口\n4. 重新加载表格数据\n\n```vue\nconst handleUpdate = (row) => {\n  data.form = JSON.parse(JSON.stringify(row)) \u002F\u002F 深拷贝一个新的对象 用于编辑  这样就不会影响行对象\n  data.formVisible = true\n}\n\nconst update = () => {\n  request.put('\u002Femployee\u002Fupdate', data.form).then(res => {  \u002F\u002F 编辑的对象里面包含id\n    if (res.code === '200') {\n      data.formVisible = false\n      ElMessage.success('操作成功')\n      load()  \u002F\u002F 更新后一定要重新加载最新的数据\n    } else {\n      ElMessage.error(res.msg)\n    }\n  })\n}\n\nconst save = () => { \u002F\u002F 在一个保存方法里面做2个操作  一个是新增 一个是编辑\n  data.form.id ? update() : add()\n}\n```\n\n![](https:\u002F\u002Fcdn.nlark.com\u002Fyuque\u002F0\u002F2024\u002Fpng\u002F751015\u002F1729238591503-ead164aa-14fb-4dd2-9b00-a87677f4d673.png)\n\n## 删除数据\n\n单个删除\n\n```vue\nconst del = (id) => {\n  ElMessageBox.confirm('删除数据后无法恢复，您确认删除吗？', '删除确认', { type: 'warning' }).then(() => {\n    request.delete('\u002Femployee\u002FdeleteById\u002F' +id).then(res => {\n      if (res.code === '200') {\n      ElMessage.success('操作成功')\n      load()  \u002F\u002F 删除后一定要重新加载最新的数据\n      } else {\n      ElMessage.error(res.msg)\n      }\n    })\n  }).catch()\n  }\n```\n\n批量删除\n\n后端接口必须使用 @RequestBody 接受数组\n\n![](https:\u002F\u002Fcdn.nlark.com\u002Fyuque\u002F0\u002F2024\u002Fpng\u002F751015\u002F1729239567816-4197504e-1572-49ce-8fe3-cf82b537500a.png)\n\n批量删除的前端代码\n\n![](https:\u002F\u002Fcdn.nlark.com\u002Fyuque\u002F0\u002F2024\u002Fpng\u002F751015\u002F1729239883520-f1b34e63-9e32-4920-bdb2-10f7db6ab1d2.png)\n\n```vue\nconst handleSelectionChange = (rows) => {  \u002F\u002F 返回所有选中的行对象数组\n  \u002F\u002F 从选中的行数组里面取出所有行的id组成一个新的数组\n  data.ids = rows.map(row => row.id)\n  console.log(data.ids)\n  }\n```\n\n```vue\nconst delBatch = () => {\n  if (data.ids.length === 0) {\n    ElMessage.warning('请选择数据')\n    return\n  }\n  ElMessageBox.confirm('删除数据后无法恢复，您确认删除吗？', '删除确认', { type: 'warning' }).then(() => {\n    request.delete('\u002Femployee\u002FdeleteBatch', { data: data.ids }).then(res => {\n      if (res.code === '200') {\n        ElMessage.success('操作成功')\n        load()  \u002F\u002F 删除后一定要重新加载最新的数据\n      } else {\n        ElMessage.error(res.msg)\n      }\n    })\n  }).catch()\n}\n```\n\n## 本节课完整的页面代码 Employee.vue\n\n```vue\n\u003Ctemplate>\n  \u003Cdiv>\n    \u003Cdiv class=\"card\" style=\"margin-bottom: 5px\">\n      \u003Cel-input style=\"width: 240px; margin-right: 10px\" v-model=\"data.name\" placeholder=\"请输入名称查询\" prefix-icon=\"Search\">\u003C\u002Fel-input>\n      \u003Cel-button type=\"primary\" @click=\"load\">查 询\u003C\u002Fel-button>\n      \u003Cel-button type=\"warning\" @click=\"reset\">重 置\u003C\u002Fel-button>\n    \u003C\u002Fdiv>\n    \u003Cdiv class=\"card\" style=\"margin-bottom: 5px\">\n      \u003Cel-button type=\"primary\" @click=\"handleAdd\">新 增\u003C\u002Fel-button>\n      \u003Cel-button type=\"danger\" @click=\"delBatch\">批量删除\u003C\u002Fel-button>\n\u003C!--      \u003Cel-button type=\"info\">导入\u003C\u002Fel-button>-->\n\u003C!--      \u003Cel-button type=\"success\">导出\u003C\u002Fel-button>-->\n    \u003C\u002Fdiv>\n    \u003Cdiv class=\"card\" style=\"margin-bottom: 5px\">\n      \u003Cel-table :data=\"data.tableData\" stripe @selection-change=\"handleSelectionChange\">\n        \u003Cel-table-column type=\"selection\" width=\"55\" \u002F>\n        \u003Cel-table-column label=\"名称\" prop=\"name\" \u002F>\n        \u003Cel-table-column label=\"性别\" prop=\"sex\" \u002F>\n        \u003Cel-table-column label=\"工号\" prop=\"no\" \u002F>\n        \u003Cel-table-column label=\"年龄\" prop=\"age\" \u002F>\n        \u003Cel-table-column label=\"个人介绍\" prop=\"description\" show-overflow-tooltip \u002F>\n        \u003Cel-table-column label=\"部门\" prop=\"departmentName\" \u002F>\n        \u003Cel-table-column label=\"操作\" width=\"120\">\n          \u003Ctemplate #default=\"scope\">\n            \u003Cel-button @click=\"handleUpdate(scope.row)\" type=\"primary\" :icon=\"Edit\" circle>\u003C\u002Fel-button>\n            \u003Cel-button @click=\"del(scope.row.id)\" type=\"danger\" :icon=\"Delete\" circle>\u003C\u002Fel-button>\n          \u003C\u002Ftemplate>\n        \u003C\u002Fel-table-column>\n      \u003C\u002Fel-table>\n      \u003Cdiv style=\"margin-top: 15px\">\n        \u003Cel-pagination\n            @size-change=\"load\"\n            @current-change=\"load\"\n            v-model:current-page=\"data.pageNum\"\n            v-model:page-size=\"data.pageSize\"\n            :page-sizes=\"[5, 10, 15, 20]\"\n            background\n            layout=\"total, sizes, prev, pager, next, jumper\"\n            :total=\"data.total\"\n        \u002F>\n      \u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n\n    \u003Cel-dialog title=\"员工信息\" v-model=\"data.formVisible\" width=\"500\">\n      \u003Cel-form :model=\"data.form\" label-width=\"80px\" style=\"padding-right: 40px; padding-top: 20px\">\n        \u003Cel-form-item label=\"名称\">\n          \u003Cel-input v-model=\"data.form.name\" autocomplete=\"off\" placeholder=\"请输入名称\" \u002F>\n        \u003C\u002Fel-form-item>\n        \u003Cel-form-item label=\"性别\">\n          \u003Cel-radio-group v-model=\"data.form.sex\">\n            \u003Cel-radio value=\"男\" label=\"男\">\u003C\u002Fel-radio>\n            \u003Cel-radio value=\"女\" label=\"女\">\u003C\u002Fel-radio>\n          \u003C\u002Fel-radio-group>\n        \u003C\u002Fel-form-item>\n        \u003Cel-form-item label=\"工号\">\n          \u003Cel-input v-model=\"data.form.no\" autocomplete=\"off\"  placeholder=\"请输入工号\" \u002F>\n        \u003C\u002Fel-form-item>\n        \u003Cel-form-item label=\"年龄\">\n          \u003Cel-input-number style=\"width: 180px\" :min=\"18\" v-model=\"data.form.age\" autocomplete=\"off\"  placeholder=\"请输入年龄\" \u002F>\n        \u003C\u002Fel-form-item>\n        \u003Cel-form-item label=\"个人介绍\">\n          \u003Cel-input :rows=\"3\" type=\"textarea\" v-model=\"data.form.description\" autocomplete=\"off\" placeholder=\"请输入个人介绍\" \u002F>\n        \u003C\u002Fel-form-item>\n      \u003C\u002Fel-form>\n      \u003Ctemplate #footer>\n        \u003Cdiv class=\"dialog-footer\">\n          \u003Cel-button @click=\"data.formVisible = false\">取 消\u003C\u002Fel-button>\n          \u003Cel-button type=\"primary\" @click=\"save\">保 存\u003C\u002Fel-button>\n        \u003C\u002Fdiv>\n      \u003C\u002Ftemplate>\n    \u003C\u002Fel-dialog>\n\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\n\u003Cscript setup>\nimport { reactive } from \"vue\";\nimport {Edit, Delete, Search} from \"@element-plus\u002Ficons-vue\"\nimport request from \"@\u002Futils\u002Frequest.js\";\nimport {ElMessage, ElMessageBox} from \"element-plus\";\n\nconst data = reactive({\n  name: null,\n  tableData: [],\n  pageNum: 1,\n  pageSize: 10,\n  total: 0,\n  formVisible: false,\n  form: {},\n  ids: []\n})\n\nconst load = () => {\n  request.get('\u002Femployee\u002FselectPage', { \u002F\u002F ?pageNum=1&pageSize=10\n    params: {\n      pageNum: data.pageNum,\n      pageSize: data.pageSize,\n      name: data.name\n    }\n  }).then(res => {\n    data.tableData = res.data.list\n    data.total = res.data.total\n  })\n}\nload()\n\nconst reset = () => {\n  data.name = null\n  load()\n}\n\nconst handleAdd = () => {\n  data.formVisible = true\n  data.form = {}\n}\n\nconst save = () => { \u002F\u002F 在一个保存方法里面做2个操作  一个是新增 一个是编辑\n  data.form.id ? update() : add()\n}\n\nconst add = () => {\n  request.post('\u002Femployee\u002Fadd', data.form).then(res => {   \u002F\u002F 新增的对象里面没有id\n    if (res.code === '200') {\n      data.formVisible = false\n      ElMessage.success('操作成功')\n      load()  \u002F\u002F 新增后一定要重新加载最新的数据\n    } else {\n      ElMessage.error(res.msg)\n    }\n  })\n}\n\nconst handleUpdate = (row) => {\n  data.form = JSON.parse(JSON.stringify(row)) \u002F\u002F 深拷贝一个新的对象 用于编辑  这样就不会影响行对象\n  data.formVisible = true\n}\n\nconst update = () => {\n  request.put('\u002Femployee\u002Fupdate', data.form).then(res => {  \u002F\u002F 编辑的对象里面包含id\n    if (res.code === '200') {\n      data.formVisible = false\n      ElMessage.success('操作成功')\n      load()  \u002F\u002F 更新后一定要重新加载最新的数据\n    } else {\n      ElMessage.error(res.msg)\n    }\n  })\n}\n\nconst del = (id) => {\n  ElMessageBox.confirm('删除数据后无法恢复，您确认删除吗？', '删除确认', { type: 'warning' }).then(() => {\n    request.delete('\u002Femployee\u002FdeleteById\u002F' +id).then(res => {\n      if (res.code === '200') {\n        ElMessage.success('操作成功')\n        load()  \u002F\u002F 删除后一定要重新加载最新的数据\n      } else {\n        ElMessage.error(res.msg)\n      }\n    })\n  }).catch()\n}\n\nconst handleSelectionChange = (rows) => {  \u002F\u002F 返回所有选中的行对象数组\n  \u002F\u002F 从选中的行数组里面取出所有行的id组成一个新的数组\n  data.ids = rows.map(row => row.id)\n  console.log(data.ids)\n}\n\nconst delBatch = () => {\n  if (data.ids.length === 0) {\n    ElMessage.warning('请选择数据')\n    return\n  }\n  ElMessageBox.confirm('删除数据后无法恢复，您确认删除吗？', '删除确认', { type: 'warning' }).then(() => {\n    request.delete('\u002Femployee\u002FdeleteBatch', { data: data.ids }).then(res => {\n      if (res.code === '200') {\n        ElMessage.success('操作成功')\n        load()  \u002F\u002F 删除后一定要重新加载最新的数据\n      } else {\n        ElMessage.error(res.msg)\n      }\n    })\n  }).catch()\n}\n\u003C\u002Fscript>\n```\n\n","coding",1,9572,1013,"2024-10-18 16:34:55","2026-05-03 22:49:02","1天学会SpringBoot3+Vue3实战项目开发","learn-springboot-vue",{"project":18,"items":19},{"id":6,"title":15,"slug":16},[20,27,34,42,49,56,63,70,77,84,85,92,99,106,113,120],{"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":14,"project_title":15,"project_slug":16},475,"OgrBbww7","01. 1天学会SpringBoot3+Vue3实战项目课程介绍",17862,910,"2024-10-11 16:50:50",{"id":28,"uuid":29,"project_id":6,"title":30,"type":9,"status":10,"public_enabled":10,"views":31,"sort":32,"created_at":33,"updated_at":14,"project_title":15,"project_slug":16},476,"U58ISSFR","02. 从0带你搭建Vue3工程",12899,911,"2024-10-11 16:47:49",{"id":35,"uuid":36,"project_id":6,"title":37,"type":9,"status":10,"public_enabled":10,"views":38,"sort":39,"created_at":40,"updated_at":41,"project_title":15,"project_slug":16},478,"tK3YUYq8","03. Vue3集成Element-Plus",9899,919,"2024-10-14 22:18:17","2026-05-07 15:33:28.189425+00",{"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},488,"J2MV6UAG","04. Element-Plus组件使用速成",8093,938,"2024-10-11 16:49:40",{"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},489,"zGi4XJsb","05. Vue3集成Vue-Router实现路由跳转",7443,939,"2024-10-12 15:44: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},499,"cwsTdvo9","06. Vue3搭建后台管理系统",7421,964,"2024-10-14 16:02:49",{"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},501,"JlXltpKA","07. Mysql语法简介（速成）",5208,973,"2024-10-15 16:52:18",{"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},509,"c3XrOTcU","08. 从0带你搭建SpringBoot3工程",9397,992,"2024-10-16 15:43:13",{"id":78,"uuid":79,"project_id":6,"title":80,"type":9,"status":10,"public_enabled":10,"views":81,"sort":82,"created_at":83,"updated_at":14,"project_title":15,"project_slug":16},516,"QsKwbDX7","09. SpringBoot3集成Mybatis",10348,1004,"2024-10-17 16:36:15",{"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":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},527,"7uED9n7e","11. Vue3开发登录注册页面",7106,1031,"2024-10-21 17:35:30",{"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},535,"poUfWrWc","12. Vue3管理系统开发个人信息、修改密码页面",5777,1050,"2024-10-22 17:50:30",{"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},542,"FxHR3hNR","13. SpringBoot3+Vue3实现文件上传下载功能",4489,1057,"2024-10-23 17:31:02",{"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},548,"VPZNSTxr","14. SpringBoot3+Vue3实现富文本编辑器功能",3931,1072,"2024-10-24 17:38:21",{"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},555,"nal0yVxM","15. SpringBoot3+Vue3实现数据批量导入导出功能",3577,1090,"2024-10-28 17:39:21",{"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},564,"XxSPPFGi","16. SpringBoot3+Vue3实现数据统计图表功能",4236,1109,"2025-01-09 09:40:57"]