图书订阅管理系统——管理员书籍管理模块

 

 如图为书籍管理模块的需求与功能点

1.书籍管理的整体设计思路总结

(1)整体的页面布局设计思路

    ——动作:管理员登陆成功先进入主页面,点击书籍管理进行入书籍管理页面,如图4个分块,主要实现前三个。

    有了这样的总体设计,首先所有页面的底部都公用,所以让其继承于主页面,那么势必要以共有部分作为父布局组件,其余通过路由跳转、又或者直接组件嵌套;公用底部,因此有了一个AdminLayOut,另外在里面设置背景颜色等基础;底部以上的头和体,则继续分,展示首页、三个底部按钮跳转的页面,他们公用左上角的icon,单独提出来,但是他们的头不一样,因此从这里形成了两组AdminHome和ManageBookLayout,AdminHome用于管理员第一次登陆的展示;ManageBookLayout用于数据管理页总组件,关于书籍管理,主要3个要实现的,他们的头、体都不一样,这里书籍管理页面以及三个功能页面也可以和AdminHome同级,这里之所以单独成ManageBookLayout,方便路由层级管理和理解,不然放一块太乱了。路由层级、文件结构如下图(右2副图)。

     

(2)增加书籍

    ——动作:管理员点击增加书籍,进入增加书籍页面,输入书籍的6个信息,点击提交

    ——实现思路:管理员点击提交后,数据会通过发送请求,服务器通过监听端口,以及请求中的路由匹配机制,解析前端提交给服务器的数据,保存到数据库中,并返回数据保存的结果。

    ——前端代码逻辑:点击按钮后,页面拿到一份管理员输入的数据,通过调用二次封装的ajax,发送POST请求,主要代码如下:

const onFinish = async (values) => {
    console.log('Received values of form: ', values, fileList);
    try {
      const response = await reqAddBook(
        {
          author: values.author,
          bookName: values.bookName,
          bookInfo: values.bookInfo,
          publisher: values.publisher,
          bookNum: values.bookNum,
          bookImg: fileList[0].thumbUrl,
        });
      console.log("请求成功", response);
      if (response.data.status === 1) {
        navigate('/admin/manageBooks/addBook', {
          replace: false
        });
      } else if (response.data.status === 0) {
        // 如果当前用户已经存在就提示一下
        alert(response.data.msg)
      }
    } catch (error) {
      console.log("请求失败", error);
    }
  }
reqAddBook=data => ajax(base.baseurl+base.addBook,data,'POST');//添加图书的接口,发送POST请求
// 服务器注册一个路由_管理员增加书籍
router.post("/admin/manageBooks/addbook",(req,res)=>{
    addBookServer(req.body,res);
})

    ——后台逻辑:服务器接收到数据后,调用addBookServer函数对数据进行进一步处理,存如数据库。但是需要注意,考虑到用户可能同一本书多次添加,本系统没有在前端去加进一步的防误触判定,询问用户是否确定保存,之在服务器端做了判定:如果是同一本书,数量改为相加后的结果。

const BookModel = require("../src/db/book");
const addBookServer = (data, res) => {

    BookModel.find({ bookName: data.bookName, author: data.author, publisher: data.publisher },(err, docs) => {
        if (docs.length > 0) {
            // 修改数据库的bookNum属性+data.bookNum就行
            let bookNum = parseInt(docs[0].bookNum)+parseInt(data.bookNum);
            console.log(bookNum)
            BookModel.updateOne({ bookName: data.bookName, author: data.author, publisher: data.publisher },{$set:{bookNum:bookNum}},(err)=>{
                if(!err) console.log('修改成功')
                console.log(err);
            })
            res.send({ msg: "数据保存成功", status: 1 })
        }
        else {
            let model = new BookModel(data)
            model.save((err) => {
                if (!err) {
                    console.log("数据保存成功");
                    res.send({ msg: "数据保存成功", status: 1 })
                } else {
                    console.log("数据保存失败")
                    res.send({ msg: `该书已存在${docs.length}本`, status: 0 })
                }
            })
        }
    })

}
module.exports = addBookServer;

基本的设计过程,3个功能点的设计都类似,代码我不一一去放了,只说一下思路和设计页面,方便理解。

(3)删除书籍

    ——动作:管理员点击删除书籍,进入删除书籍页面,输入书籍作者和书名,点击删除按钮,每次删除都把数据库的最新的5条消息返回展示在前端

    ——实现思路:管理员点击提交后,数据会通过发送请求,服务器通过监听端口,以及请求中的路由匹配机制,解析前端提交给服务器的数据,进行数据库数据的更新,并返回数据删除后的结果和删除日志记录。

    ——前端代码逻辑:点击按钮后,页面拿到一份管理员输入的数据,通过调用二次封装的ajax,发送POST请求;接收到后端返回的日志,保存到本地状态以及localStorge,前者保证”热更新“,后者保证当前页面无操作刷新或者别的页面跳转到当前页面时,页面的日志数据不会消失。在渲染的时候注意写法,先判断本地state,在判断localStorge,这个我还另写了一篇随笔简单介绍

    ——后端代码逻辑:服务器拿到数据后,先进行删除,如果删除结果中,删除数量>0,说明成功执行了删除,非无效删除(本没有这个书时进行的删除),保存删除记录,成功后返回最新的5条删除记录。

(4)更改书籍

    ——动作:管理员点击更改书籍,进入更改书籍页面,输入书籍作者和书名,点击检索按钮,如果能检索到,结果会作为输入框的默认值展示,否则会提示,没有这本书

    ——实现思路:管理员点击提交后,数据会通过发送请求,服务器通过监听端口,以及请求中的路由匹配机制,解析前端提交给服务器的数据。在这个功能模块里进行了两次请求发送,第一次检索,第二次数据更新,每次都返回数据更新结果。

    ——前端代码逻辑:点击按钮后,页面拿到一份管理员输入的数据,通过调用二次封装的ajax,发送POST请求;接收到后端返回的书籍信息,保存到本地state,作为输入框默认输入,管理员根据提示进一步填写数据并提交更新数据,在接受后台更新状态结果

    ——后端代码逻辑:服务器第一次拿到数据后,先进行检索,返回检索结果;第二次接收到服务器数据,进行数据更新。

   

 

 (5)补充主页展示

  主页:搜索框、推荐书籍展示、轮播图设置三个功能。

  轮播图直接采用的antd4的样式;整体的设计逻辑是,点击设置---》出现图2,搜索框搜索书籍,数据展示在上方===》选择想要检索的书籍===》在下方选择想要放在轮播图中的书籍===》点击提交,回到图1。

===》

搜索框不只是为了轮播图服务,它的意义还是用来检索,在用户只知道书名或者作者的时候(目前的设计就是只输入一种,要么作者,要么书名,且暂时不支持模糊搜索,也很好修改,服务器端进行字符串匹配进行),轮播图这块出的问题最多,关于消息订阅,同一个uid同一个页面内才有效,页面一旦刷新,useEffert副作用函数返回值消除副作用时会导致消息订阅不到;useEffert的监听机制也是没真的搞清,之前单独写过一个组件是否能在订阅的同时发布?是否可以同时订阅多个?但是没有仔细研究第二参数不同情况下的监听效果,后面做完管理员的所有任务,就把这个具体做一下,更在它后面

 

 

 

 

 

 

 

 

posted @ 2022-08-25 21:37  乔十六  阅读(388)  评论(0编辑  收藏  举报