[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"article-public-ptdUZ7z8":3,"public-project-articles-ptdUZ7z8":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},1172,"ptdUZ7z8",57,"04. 零基础小白直接上手FastAPI+Vue3前后端分离开发","## vue 安装 axios 插件\n\n```javascript\n npm i axios -S\n```\n\n## 跨域配置\n\n```javascript\nserver: {\n  proxy: {\n    '\u002Fapi': {\n      target: 'http:\u002F\u002F127.0.0.1:9090',\n        changeOrigin: true,\n        rewrite: (path) => path.replace(\u002F^\\\u002Fapi\u002F, '')\n    }\n  }\n},\n\n\u002F\u002F 请求方式：\nconst ip = \"\u002Fapi\"\n\naxios.get(ip + '\u002Fstudent\u002FselectPage')\n```\n\n## 新增数据\n\nDialog 弹窗\n\n```vue\n\u003Cel-dialog v-model=\"dialogVisible\" title=\"学生信息\" width=\"800\">\n      \u003Cel-form :model=\"form\">\n        \u003Cel-form-item label=\"Promotion name\" :label-width=\"formLabelWidth\">\n          \u003Cel-input v-model=\"form.name\" autocomplete=\"off\" \u002F>\n        \u003C\u002Fel-form-item>\n      \u003C\u002Fel-form>\n\n      \u003Ctemplate #footer>\n          \u003Cdiv class=\"dialog-footer\">\n            \u003Cel-button @click=\"dialogVisible = 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\n\n## 本节课完整的页面代码\n\n```vue\n\u003Ctemplate>\n  \u003Cdiv>\n    \u003Cdiv style=\"text-align: center; font-size: 30px; margin-bottom: 20px; font-weight: bold\">青哥哥带你学习FastAPI + Vue3\u003C\u002Fdiv>\n    \u003Cdiv style=\"text-align: center; margin-bottom: 50px; font-size: 18px\">学生信息管理页面（增删改查）\u003C\u002Fdiv>\n    \u003Cdiv style=\"width: 70%; margin: 30px auto\">\n      \u003Cdiv style=\"margin-bottom: 10px\">\n        \u003Cel-input clearable @clear=\"load\" style=\"width: 300px; margin-right: 5px\" v-model=\"data.no\" placeholder=\"请输入学号查询\">\u003C\u002Fel-input>\n        \u003Cel-input clearable @clear=\"load\" style=\"width: 300px\" v-model=\"data.name\" placeholder=\"请输入姓名查询\">\u003C\u002Fel-input>\n        \u003Cel-button type=\"info\" @click=\"load\" style=\"margin-left: 5px; margin-right: 20px\">搜索\u003C\u002Fel-button>\n        \u003Cel-button type=\"primary\" @click=\"handleAdd\">新增\u003C\u002Fel-button>\n      \u003C\u002Fdiv>\n\n      \u003Cdiv>\n        \u003Cel-table border stripe :data=\"data.tableData\" style=\"width: 100%\">\n          \u003Cel-table-column prop=\"id\" label=\"ID\" width=\"70\" \u002F>\n          \u003Cel-table-column prop=\"no\" label=\"学号\" \u002F>\n          \u003Cel-table-column prop=\"name\" label=\"姓名\" \u002F>\n          \u003Cel-table-column prop=\"clazz\" label=\"班级\" \u002F>\n          \u003Cel-table-column prop=\"major\" label=\"专业\" \u002F>\n          \u003Cel-table-column prop=\"college\" label=\"学院\" \u002F>\n          \u003Cel-table-column prop=\"phone\" label=\"手机号\" \u002F>\n          \u003Cel-table-column prop=\"email\" label=\"邮箱\" \u002F>\n          \u003Cel-table-column prop=\"address\" label=\"地址\" \u002F>\n          \u003Cel-table-column label=\"操作\" width=\"150\">\n            \u003Ctemplate #default=\"scope\">\n              \u003Cel-button size=\"small\" type=\"primary\" @click=\"handleEdit(scope.row)\">编辑\u003C\u002Fel-button>\n              \u003Cel-button size=\"small\" type=\"danger\" @click=\"remove(scope.row.id)\">删除\u003C\u002Fel-button>\n            \u003C\u002Ftemplate>\n          \u003C\u002Fel-table-column>\n        \u003C\u002Fel-table>\n      \u003C\u002Fdiv>\n      \u003Cdiv style=\"margin-top: 10px\">\n        \u003Cel-pagination background layout=\"total, prev, pager, next\" @current-change=\"load\" v-model:current-page=\"data.pageNum\"\n                       v-model:page-size=\"data.pageSize\" :total=\"data.total\" \u002F>\n      \u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n\n    \u003Cel-dialog v-model=\"data.dialogVisible\" title=\"学生信息\" width=\"30%\" destroy-on-close>\n      \u003Cel-form ref=\"formRef\" :model=\"data.form\" :rules=\"data.rules\" label-width=\"70px\" style=\"padding: 20px\">\n        \u003Cel-form-item prop=\"no\" label=\"学号\">\n          \u003Cel-input :disabled=\"data.form.id > 0\" v-model=\"data.form.no\" autocomplete=\"off\" placeholder=\"请输入学号\" \u002F>\n        \u003C\u002Fel-form-item>\n        \u003Cel-form-item prop=\"name\" label=\"姓名\">\n          \u003Cel-input v-model=\"data.form.name\" autocomplete=\"off\" placeholder=\"请输入姓名\" \u002F>\n        \u003C\u002Fel-form-item>\n        \u003Cel-form-item prop=\"clazz\" label=\"班级\">\n          \u003Cel-input v-model=\"data.form.clazz\" autocomplete=\"off\" placeholder=\"请输入班级\" \u002F>\n        \u003C\u002Fel-form-item>\n        \u003Cel-form-item prop=\"major\" label=\"专业\">\n          \u003Cel-input v-model=\"data.form.major\" autocomplete=\"off\" placeholder=\"请输入专业\" \u002F>\n        \u003C\u002Fel-form-item>\n        \u003Cel-form-item prop=\"college\" label=\"学院\">\n          \u003Cel-input v-model=\"data.form.college\" autocomplete=\"off\" placeholder=\"请输入学院\" \u002F>\n        \u003C\u002Fel-form-item>\n        \u003Cel-form-item prop=\"phone\" label=\"手机号\">\n          \u003Cel-input v-model=\"data.form.phone\" autocomplete=\"off\" placeholder=\"请输入手机号\" \u002F>\n        \u003C\u002Fel-form-item>\n        \u003Cel-form-item prop=\"email\" label=\"邮箱\">\n          \u003Cel-input v-model=\"data.form.email\" autocomplete=\"off\" placeholder=\"请输入邮箱\" \u002F>\n        \u003C\u002Fel-form-item>\n        \u003Cel-form-item prop=\"address\" label=\"地址\">\n          \u003Cel-input type=\"textarea\" v-model=\"data.form.address\" 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.dialogVisible = 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\n\u003Cscript setup>\nimport {reactive, ref} from \"vue\";\nimport axios from \"axios\";\nimport {ElMessage, ElMessageBox} from \"element-plus\";\n\nconst formRef = ref()\nconst ip = \"\u002Fapi\"\nconst data = reactive({\n  no: null,\n  name: null,\n  pageNum: 1,\n  pageSize: 5,\n  total: 0,\n  tableData: [],\n  dialogVisible: false,\n  form: {},\n  rules: {\n    no: [\n      { required: true, message: '请输入学号', tigger: blur }\n    ],\n    name: [\n      { required: true, message: '请输入姓名', tigger: blur }\n    ]\n  }\n})\n\nconst handleAdd = () => {\n  \u002F\u002F 新增数据\n  data.dialogVisible = true\n  data.form = {}\n}\n\nconst handleEdit = (row) => {\n  data.form = JSON.parse(JSON.stringify(row))  \u002F\u002F 深拷贝\n  data.dialogVisible = true\n}\n\nconst add = () => {\n  axios.post(ip + '\u002Fstudent\u002Fadd', data.form).then(res => {\n    if (res.status === 200) {  \u002F\u002F成功\n      data.dialogVisible = false  \u002F\u002F 关闭弹窗\n      load()\n      ElMessage.success('新增成功')\n    } else {\n      ElMessage.error('新增失败')\n    }\n  })\n}\n\nconst update = () => {\n  axios.put(ip + '\u002Fstudent\u002Fupdate', data.form).then(res => {\n    if (res.status === 200) {  \u002F\u002F成功\n      data.dialogVisible = false  \u002F\u002F 关闭弹窗\n      load()\n      ElMessage.success('修改成功')\n    } else {\n      ElMessage.error('修改失败')\n    }\n  })\n}\n\nconst save = () => {\n  formRef.value.validate(valid => {\n    if (valid) {  \u002F\u002F 验证通过\n      if (data.form.id) {  \u002F\u002F 编辑\n        update()\n      } else {  \u002F\u002F 新增\n        add()\n      }\n    }\n  })\n}\n\nconst remove = (id) => {\n  ElMessageBox.confirm('删除后数据无法恢复，确定删除吗？', '删除确认', { type: 'warning' }).then(res => {\n    \u002F\u002F 根据ID删除数据\n    axios.delete(ip + '\u002Fstudent\u002Fdelete\u002F' + id).then(res => {\n      if (res.status === 200) {  \u002F\u002F成功\n        load()\n        ElMessage.success('删除成功')\n      } else {\n        ElMessage.error('删除失败')\n      }\n    })\n  }).catch(err => {})\n}\n\nconst load = () => {\n  axios.get(ip + '\u002Fstudent\u002FselectPage', {\n    params: {\n      pageNum: data.pageNum,\n      pageSize: data.pageSize,\n      no: data.no,\n      name: data.name\n    }\n  }).then(res => {\n    data.tableData = res.data.list\n    data.total = res.data.total\n  })\n}\nload()  \u002F\u002F 加载数据\n\u003C\u002Fscript>\n\n\n\u003Cstyle scoped>\n\n\u003C\u002Fstyle>\n\n```\n\n","coding",1,308,2292,"2026-01-07 16:54:01","2026-05-03 22:49:02","FastAPI+Vue3零基础入门教程","fastapi-vue-zero",{"project":18,"items":19},{"id":6,"title":15,"slug":16},[20,27,34,42,43],{"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},1162,"v00b56h7","01. 零基础小白直接上手Vue",847,2271,"2026-01-04 18:10:36",{"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},1165,"w9DeSyXA","02. 零基础小白直接上手FastAPI",446,2275,"2026-01-05 17:01:37",{"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},1167,"p7VJICb3","03. 零基础小白直接上手FastAPI开发增删改查接口",371,2279,"2026-01-06 17:43:27","2026-05-07 15:36:12.649662+00",{"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":44,"uuid":45,"project_id":6,"title":46,"type":9,"status":10,"public_enabled":10,"views":47,"sort":48,"created_at":49,"updated_at":14,"project_title":15,"project_slug":16},1173,"ngdkfhqL","05. 课程完整源码",194,2293,"2026-01-07 16:56:13"]