[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"article-public-h0SZsjkz":3,"public-project-articles-h0SZsjkz":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},1189,"h0SZsjkz",58,"05. 使用AI帮助开发图书列表页面和详情展示页面","## UserBooks.vue\n\n```vue\n\u003Ctemplate>\n  \u003Cdiv>\n    \u003Cdiv style=\"margin-bottom: 30px; display: flex; align-items: center\">\n      \u003Cdiv style=\"flex: 1\">\n        \u003Cdiv style=\"display: flex; align-items: center\">\n          \u003Cdiv @click=\"changeCategory(null)\" style=\"padding-bottom: 5px; margin-right: 20px; cursor: pointer\" :class=\"{'category-active' : data.activeCategoryId === null }\">全部图书\u003C\u002Fdiv>\n          \u003Cdiv @click=\"changeCategory(item.id)\" style=\"padding-bottom: 5px; margin-right: 20px; cursor: pointer\" :class=\"{'category-active' : data.activeCategoryId === item.id }\" v-for=\"item in data.categoryList\" :key=\"item.id\">{{ item.name }}\u003C\u002Fdiv>\n        \u003C\u002Fdiv>\n      \u003C\u002Fdiv>\n      \u003Cdiv>\n        \u003Cel-input clearable @clear=\"load\" style=\"width: 300px; height: 40px\" v-model=\"data.name\" placeholder=\"请输入图书名称、作者或ISBN搜索\">\u003C\u002Fel-input>\n        \u003Cel-button type=\"primary\" style=\"height: 40px; margin-left: 10px\" @click=\"load\">搜 索\u003C\u002Fel-button>\n      \u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n\n    \u003Cel-row :gutter=\"20\">\n      \u003Cel-col :span=\"6\" style=\"margin-bottom: 20px\" v-for=\"item in data.tableData\" :key=\"item.id\">\n        \u003Cdiv class=\"card item\" style=\"padding: 0; cursor: pointer\" @click=\"router.push('\u002Fmanager\u002FbookDetail?id=' + item.id)\">\n          \u003Cimg style=\"width: 100%; height: 450px; border-radius: 5px 5px 0 0;\" :src=\"item.img\" alt=\"\">\n          \u003Cdiv style=\"padding: 10px\">\n            \u003Cdiv style=\"font-size: 18px; margin-bottom: 10px; font-weight: bold; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;\">{{ item.name }}\u003C\u002Fdiv>\n            \u003Cdiv style=\"color: #666; font-size: 14px; margin-bottom: 10px\">作者：{{ item.author }}\u003C\u002Fdiv>\n            \u003Cdiv style=\"display: flex; align-items: center\">\n              \u003Cdiv style=\"flex: 1\">\n                \u003Cdiv style=\"color: #f56c6c; font-size: 20px; font-weight: bold\">￥{{ item.price }}\u003C\u002Fdiv>\n              \u003C\u002Fdiv>\n              \u003Cdiv style=\"color: #999; font-size: 13px\">{{ item.publisher }}\u003C\u002Fdiv>\n            \u003C\u002Fdiv>\n          \u003C\u002Fdiv>\n        \u003C\u002Fdiv>\n      \u003C\u002Fel-col>\n    \u003C\u002Fel-row>\n\n    \u003Cdiv v-if=\"data.total\" style=\"margin-top: 20px; margin-bottom: 50px\">\n      \u003Cel-pagination @current-change=\"load\" layout=\"total, prev, pager, next\" :page-size=\"data.pageSize\" v-model:current-page=\"data.pageNum\" :total=\"data.total\"\u002F>\n    \u003C\u002Fdiv>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\n\u003Cscript setup>\nimport { reactive } from \"vue\";\nimport request from \"@\u002Futils\u002Frequest.js\";\nimport router from \"@\u002Frouter\u002Findex.js\";\nimport { ElMessage } from \"element-plus\";\n\nconst data = reactive({\n  user: JSON.parse(localStorage.getItem('xm-user') || '{}'),\n  tableData: [],\n  total: 0,\n  pageNum: 1,  \u002F\u002F 当前的页码\n  pageSize: 8,  \u002F\u002F 每页的个数\n  name: null,\n  activeCategoryId: null,\n  categoryList: []\n})\n\n\u002F\u002F 加载分类列表数据\nrequest.get('\u002Fcategory\u002FselectAll').then(res => {\n  if (res.code === '200') {\n    data.categoryList = res.data\n  }\n})\n\n\u002F\u002F 切换分类\nconst changeCategory = (categoryId) => {\n  data.activeCategoryId = categoryId\n  data.pageNum = 1\n  load()\n}\n\n\u002F\u002F 加载图书分页数据\nconst load = () => {\n  request.get('\u002Fbooks\u002FselectPage', {\n    params: {\n      pageNum: data.pageNum,\n      pageSize: data.pageSize,\n      name: data.name,\n      categoryId: data.activeCategoryId\n    }\n  }).then(res => {\n    if (res.code === '200') {\n      data.tableData = res.data?.list || []\n      data.total = res.data?.total\n    } else {\n      ElMessage.error(res.msg)\n    }\n  })\n}\nload()\n\u003C\u002Fscript>\n\n\u003Cstyle scoped>\n.item {\n  transition: all 0.5s;\n  background-color: white;\n  border-radius: 5px;\n  box-shadow: 0 2px 12px 0 rgba(0,0,0,0.1);\n}\n.item:hover {\n  transform: translateY(-5px);\n}\n.category-active {\n  color: #006cff;\n  border-bottom: 2px solid #006cff;\n}\n\u003C\u002Fstyle>\n```\n\n## BookDetail.vue\n\n```vue\n\u003Ctemplate>\n  \u003Cdiv style=\"width: 70%; margin:  0 auto; padding: 20px\" class=\"card\">\n    \u003Cdiv style=\"margin-bottom: 20px\">\n      \u003Ch1 style=\"font-size: 26px; color: #111; margin-bottom: 20px\">{{ data.book.name }}\u003C\u002Fh1>\n    \u003C\u002Fdiv>\n\n    \u003Cdiv style=\"display: flex; gap: 30px; margin-bottom: 40px\">\n      \u003Cdiv style=\"width: 155px\">\n        \u003Cimg :src=\"data.book.img\" style=\"width: 155px; height: 230px; border-radius: 4px; box-shadow: 0 1px 3px rgba(0,0,0,0.2)\" \u002F>\n      \u003C\u002Fdiv>\n\n      \u003Cdiv style=\"flex: 1; font-size: 14px; color: #666; line-height: 24px\">\n        \u003Cdiv style=\"margin-bottom: 5px\">\u003Cspan style=\"color: #111\">作者:\u003C\u002Fspan> \u003Cspan style=\"color: #666\">{{ data.book.author }}\u003C\u002Fspan>\u003C\u002Fdiv>\n        \u003Cdiv style=\"margin-bottom: 5px\">\u003Cspan style=\"color: #111\">出版社:\u003C\u002Fspan> {{ data.book.publisher }}\u003C\u002Fdiv>\n        \u003Cdiv style=\"margin-bottom: 5px\">\u003Cspan style=\"color: #111\">出版年:\u003C\u002Fspan> {{ data.book.year }}\u003C\u002Fdiv>\n        \u003Cdiv style=\"margin-bottom: 5px\">\u003Cspan style=\"color: #111\">定价:\u003C\u002Fspan> \u003Cspan style=\"color: #f56c6c; font-weight: bold\">￥{{ data.book.price }}\u003C\u002Fspan>\u003C\u002Fdiv>\n        \u003Cdiv style=\"margin-bottom: 5px\">\u003Cspan style=\"color: #111\">ISBN:\u003C\u002Fspan> {{ data.book.isbn }}\u003C\u002Fdiv>\n        \u003Cdiv style=\"margin-bottom: 5px\">\u003Cspan style=\"color: #111\">分类:\u003C\u002Fspan> {{ data.book.categoryName }}\u003C\u002Fdiv>\n\n        \u003Cdiv style=\"margin-top: 20px\">\n          \u003Cel-button type=\"warning\" plain @click=\"collect\">收藏\u003C\u002Fel-button>\n          \u003Cel-button type=\"primary\" plain @click=\"handleComment\">去评论\u003C\u002Fel-button>\n        \u003C\u002Fdiv>\n      \u003C\u002Fdiv>\n\n      \u003Cdiv style=\"width: 200px; border-left: 1px solid #eee; padding-left: 20px\">\n        \u003Cdiv style=\"color: #999; font-size: 12px\">图书评分\u003C\u002Fdiv>\n        \u003Cdiv style=\"display: flex; align-items: center; gap: 10px; margin-top: 5px\">\n          \u003Cspan style=\"font-size: 28px; color: #111\">9.2\u003C\u002Fspan>\n          \u003Cel-rate v-model=\"data.rate\" disabled \u002F>\n        \u003C\u002Fdiv>\n        \u003Cdiv style=\"color: #37a; font-size: 12px; margin-top: 10px\">12040人评价\u003C\u002Fdiv>\n      \u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n\n    \u003Cdiv style=\"margin-top: 40px\">\n      \u003Cdiv style=\"font-size: 16px; color: #007722; margin-bottom: 10px; font-weight: bold\">内容简介 · · · · · ·\u003C\u002Fdiv>\n      \u003Cdiv style=\"font-size: 14px; color: #111; line-height: 1.6; white-space: pre-wrap\">\n        {{ data.book.description || '暂无简介' }}\n      \u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n\n     \u003Cdiv style=\"margin-top: 40px\">\n      \u003Cdiv style=\"font-size: 16px; color: #007722; margin-bottom: 10px; font-weight: bold\">图书评价 · · · · · ·\u003Cspan style=\"color: #37a\">（全部12040条）\u003C\u002Fspan>\u003C\u002Fdiv>\n      \u003Cdiv style=\"font-size: 14px; color: #111; line-height: 1.6; white-space: pre-wrap\">\n        暂无评价\n      \u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\n\u003Cscript setup>\nimport { reactive } from \"vue\";\nimport request from \"@\u002Futils\u002Frequest.js\";\nimport { useRoute } from \"vue-router\";\nimport { ElMessage } from \"element-plus\";\n\nconst route = useRoute()\n\nconst data = reactive({\n  id: route.query.id,\n  book: {},\n  rate: 4.5\n})\n\n\u002F\u002F 获取图书详情\nconst load = () => {\n  request.get('\u002Fbooks\u002FselectById\u002F' + data.id).then(res => {\n    if (res.code === '200') {\n      data.book = res.data || {}\n    } else {\n      ElMessage.error(res.msg)\n    }\n  })\n}\n\nconst collect = () => {\n  ElMessage.success(\"已加入收藏列表\")\n}\n\nconst handleComment = () => {\n  ElMessage.info(\"前往评论...\")\n}\n\nload()\n\u003C\u002Fscript>\n\n\u003Cstyle scoped>\n\u002F* 保持你的简洁风格，基本不写 class *\u002F\nh1 {\n  word-break: break-all;\n}\n\u003C\u002Fstyle>\n```\n\n\n\n根据  分类 id 查询\n\n```python\n# 分页查询\n@router.get(\"\u002FselectPage\")\nasync def select_page(name: str = \"\", categoryId: int = 0, pageNum: int = 1, pageSize: int = 10):\n    # 同时获取分页数据和总数\n    query = Books.filter(name__contains=name).prefetch_related(\"category\")\n    if categoryId > 0:\n        query = query.filter(category__id=categoryId)\n    # 获取分页数据\n    books_list = await query.order_by(\"-id\").offset((pageNum - 1) * pageSize).limit(pageSize)\n    books_list = [\n        {\n            **BooksPydantic.model_validate(books).model_dump(),\n            \"categoryId\": books.category.id if books.category else None,\n            \"categoryName\": books.category.name if books.category else None,\n        }\n        for books in books_list\n    ]\n    # 计算总数\n    total = await query.count()\n    # 封装分页数据\n    pageinfo = PageInfo(total=total, list=books_list)\n    return Result.success(pageinfo)\n\n```\n\n单个查询\n\n```python\n# 单个查询\n@router.get(\"\u002FselectById\u002F{books_id}\")\nasync def select_one(books_id: int):\n    books = await Books.get_or_none(id=books_id).prefetch_related(\"category\")\n    book_dict = BooksPydantic.model_validate(books).model_dump()  # 转换成字典数据\n    book_dict['categoryName'] = books.category.name if books.category else None\n    return Result.success(book_dict)\n\n```\n\n","coding",1,110,2318,"2026-01-12 17:27:25","2026-05-03 22:49:02","基于FastAPI+Vue3+推荐算法的图书推荐系统","book-recommendation",{"project":18,"items":19},{"id":6,"title":15,"slug":16},[20,27,34,41,48,55],{"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},1174,"NzsRyEPn","00. 课程相关资料获取",308,2297,"2026-04-19 17:28:24",{"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},1180,"oRHLGeOy","01. 图书推荐系统介绍",182,2304,"2026-01-09 11:50:58",{"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":14,"project_title":15,"project_slug":16},1181,"NrrW311Q","02. 导入并运行项目脚手架",154,2306,"2026-01-09 18:33:00",{"id":42,"uuid":43,"project_id":6,"title":44,"type":9,"status":10,"public_enabled":10,"views":45,"sort":46,"created_at":47,"updated_at":14,"project_title":15,"project_slug":16},1182,"UgkPAWGn","03. 开发图书分类信息管理功能",128,2307,"2026-01-09 18:33:16",{"id":49,"uuid":50,"project_id":6,"title":51,"type":9,"status":10,"public_enabled":10,"views":52,"sort":53,"created_at":54,"updated_at":14,"project_title":15,"project_slug":16},1183,"8k9XX7Tv","04. 开发图书信息管理功能",126,2308,"2026-01-09 18:34:50",{"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}]