图书订阅管理系统——用户设计与整个项目总结

1.用户设计

用户设计主要是三个大方面、用户主页、用户订阅、用户个人信息(这个和管理员设计成一个了后面统一说)

  

 

 2.图片1

  1.  用户主页、轮播图——书籍推荐,这里和管理员用户类似,管理员设置,并在数据库存档,用户这里刷新就会出现,第一次点击刷新后数据会进行缓存,以后就会采用缓存数据,组件逻辑设计如下:
  2. 建立状态用于存储从数据库获取的轮播图数据,因此,在设计组件的结构时,使用的是:如果状态不为空使用状态渲染;否则若缓存不为空,使用缓存渲染;否则显示暂无数据;
  3. 考虑到页面第一次加载会在还没有进行操作时进行渲染,因此要对本地缓存进行判空,如果为null,赋值【】,否则它是没有map属性的,数据数据渲染常用的就是map。看代码:
import React, { useState } from 'react'
import { Carousel } from 'antd';
import '../../../../assets/iconfont.css'
import './style.less'
import HomeBooks from '../../../AdminLayout/AdminHome/Adminbody/HomeBooks'
import { reqgetcrollChartData } from '../../../../api/index-ajax';
export default function UserHomeBody() {
  const [crollChart,setcrollChart] = useState([]);
  let current = localStorage.getItem('crollChart');
  if(current===null) current=[];
  else current = JSON.parse(localStorage.getItem('crollChart'));
  const contentStyle = {
    height: '160px',
    width: '300px',
    color: '#fff',
    margin: '0 auto',
    lineHeight: '160px',
    textAlign: 'center',
    background: '#364d79',
  };
  const getcrollChartData = async()=>{
    const response = await reqgetcrollChartData({});
    console.log(response)
    setcrollChart(response.data.data);
    localStorage.setItem('crollChart',JSON.stringify(response.data.data))
  }
  return (
    <div>
      <div className="crollChartWrapper">
        <div className="crollBooks">
          <Carousel autoplay>
            {
              crollChart.length !== 0 ? crollChart.map((imgObj) => {
                return (
                  <div key={imgObj.id}>
                    <img style={contentStyle} src={imgObj.bookImg} alt="加载失败或未设置轮播图书籍" />
                  </div>
                )
              }) :current.length!==0 ?
              current.map((imgObj) => {
                return (
                  <div key={imgObj.id}>
                    <img style={contentStyle} src={imgObj.bookImg} alt="加载失败或未设置轮播图书籍" />
                  </div>
                )
              }) : <div>暂无数据</div>
            }
          </Carousel>
        </div>
        <div className='getcrollChartData'>
          <span onClick={()=>getcrollChartData()} className='iconfont icon-shuaxin'></span>
        </div>

      </div>
      <div className="bookList">
        <HomeBooks state={current} />
      </div>
    </div>
  )
}

3.图片2、3

 书籍小车表示订阅的申请列表,2是列表,3是申请所需要的信息,在图2点击【去订阅】,跳转到图3,搜索书籍,点击进行选择,选择订阅开始时间和结束时间,点击按钮,就会产生订阅申请,点击【书籍小车】返回到订阅申请列表页,这里并非是在本地缓存中进行申请记录保存,而是只在数据库,点击刷新,就可以将数据进行渲染,用户也同时了解订阅的进度(三个状态:【申请中】【同意申请】【拒绝申请】)。本地缓存在当下一次页面跳转时,antd组件的选择功能失效了,因此去掉了。这个页面也添加了取消订阅用来让用户进行删除订阅申请。(突然想起管理员要同意申请的话,在现实里应该是取了书才进行数据库数量-1吧,这只是产生一个凭证)。

import React, { useState } from 'react'
import IconToFirstPage from '../../../components/IconToFirstPage'
import './style.less'
import { Checkbox, Col, Row, Button } from 'antd';
import { NavLink } from 'react-router-dom';
import { reqDeleteSub, reqGetSubApplyList } from '../../../api/index-ajax';
export default function SubBook() {
  // 创建状态
  const [subList, setsubList] = useState([]);
  const [deleteSub,setDeleteSub] = useState();
  // let current = localStorage.getItem("subList");
  // console.log();
  // if(current===null) current=[];
  // else current = JSON.parse(current)
  const onChange = (checkedValues) => {
    console.log('checked = ', checkedValues);
    setDeleteSub(checkedValues);
    // console.log(selectBooks);
  };
  const toShift = async()=>{
    try {
      const response = await reqGetSubApplyList({applyPerson:JSON.parse(localStorage.getItem('userInfo')).username});
      console.log(response);
      if(response.data.status===1) {
        setsubList(response.data.data);
        alert(response.data.msg)
        // localStorage.setItem('subList',JSON.stringify(response.data.data))
      }else{
        alert(response.data.msg)
        setsubList(response.data.data);
        // localStorage.setItem('subList',JSON.stringify(response.data.data))
      }
    } catch (error) {
      console.log("请求失败",error)
    }
  }
  
  const todelSub = async()=>{
    try{
      const response = await reqDeleteSub({values:deleteSub});
      alert(response.data.msg);
    }catch(error){
      console.log(error)
    }
  }
  return (
    <div className='subBookWrapper'>
      <div className="subBookheader">
        <IconToFirstPage />
        <div className='subBook-title'><span>书籍订阅列表</span></div>
        <NavLink to='/user/searchResult'><div className="lastPage"><span>去订阅</span></div></NavLink>
      </div>
      <div className="subListWrapper">
        <div className='subListContainer'>
          <div className="subListBodyTitle">
            <div className="applyPerson"><span>申请人</span></div>
            <div className="applyBook"><span>书籍</span></div>
            <div className="applyBookTime"><span>申请时间</span></div>
            <div className="subStartTime"><span>订阅开始</span></div>
            <div className="subEndTime"><span>订阅结束</span></div>
            <div className="subStatus"><span>状态</span></div>
          </div>
          <div className="booksCheckbox">
            <Checkbox.Group style={{ width: '100%', }} onChange={onChange} >
              {  subList.length !== 0 ? subList.map((bookObj) => {
                  return (
                    <Row className='row' key={bookObj._id}>
                      <Col span={50}>
                        <Checkbox value={bookObj}>
                          <div className="applyListData">
                            <div className="applyPerson"><span>{bookObj.applyPerson}</span></div>
                            <div className="applyBook"><span>{bookObj.applyBook}</span></div>
                            <div className="applyBookTime"><span>{bookObj.applyBookTime}</span></div>
                            <div className="subStartTime"><span>{bookObj.subStartTime}</span></div>
                            <div className="subEndTime"><span>{bookObj.subEndTime}</span></div>
                            <div className="subStatus"><span>{bookObj.subStatus}</span></div>
                          </div>
                        </Checkbox>
                      </Col>
                    </Row>
                  )
                })
                // :
                // current.length !== 0 ? current.map((bookObj) => {
                //   return (
                //     <Row className='row' key={bookObj._id}>
                //       <Col span={50}>
                //         <Checkbox value={bookObj}>
                //           <div className="applyListData">
                //             <div className="applyPerson"><span>{bookObj.applyPerson}</span></div>
                //             <div className="applyBook"><span>{bookObj.applyBook}</span></div>
                //             <div className="applyBookTime"><span>{bookObj.applyBookTime}</span></div>
                //             <div className="subStartTime"><span>{bookObj.subStartTime}</span></div>
                //             <div className="subEndTime"><span>{bookObj.subEndTime}</span></div>
                //             <div className="subStatus"><span>{bookObj.subStatus}</span></div>
                //           </div>
                //         </Checkbox>
                //       </Col>
                //     </Row>
                //   )
                // }) 
                : 
                <div>暂无书籍可供选择,请搜索书籍</div>
              }
            </Checkbox.Group>
          </div>
        </div>
      </div>
      <div className="subListFooter">
        <Button type="primary" htmlType="submit" onClick={() => toShift()}>刷新数据</Button>
        <Button type="primary" htmlType="submit" onClick={() => todelSub()}>取消订阅</Button>
      </div>
    </div>
  )
}

 

 最后的时个人信息管理:antd组件库里的form表单进行组合制造了一个用户个人信息表,根据提示,若是修改,就点击上面的选择点,进行信息填写,然后提交,重新登陆即可,

import React, { useState } from 'react'
import IconToFirstPage from '../../../components/IconToFirstPage'
import './style.less'
import {
    Form,
    Input,
    Button,
    Checkbox,
} from 'antd';
import { useNavigate } from 'react-router-dom';
import { reqChangSelfInfo, reqDeleteSelf } from '../../../api/index-ajax';



export default function SelfInfo() {
    let current={}
    if(localStorage.getItem("userInfo")!==undefined) current = JSON.parse(localStorage.getItem("userInfo"));
    
    console.log(current)
    const navigate = useNavigate();
    const toDeleteSelf = async()=>{
        try {
            const response = await reqDeleteSelf({username:current.username,identify:current.identify});
            if(response.data.status===1) navigate('/register');
        } catch (error) {
            console.log("请求失败",error)
        }
        
    }
    const toExit = ()=>{
        navigate('/login');
    }
    const FormDisabledDemo = () => {
        const [componentDisabled, setComponentDisabled] = useState(true);
    
        const onFormLayoutChange = ({ disabled }) => {
            setComponentDisabled(disabled);
        };
        const onFinish = async(values) => {
            values.identify = current.identify;
            values.preUsername = current.username;
            console.log('Success:', values);
            try {
                const response =await reqChangSelfInfo({values:values});
                console.log(response);
                if(response.data.status===1) navigate('/login')
            } catch (error) {
                console.log("请求出错",error)
            }
        };
    
        const onFinishFailed = (errorInfo) => {
            console.log('Failed:', errorInfo);
        };
        
        return (
            <>
                <Checkbox
                    checked={componentDisabled}
                    onChange={(e) => setComponentDisabled(e.target.checked)}
                >
                    点击可进行修改个人信息,修改完点击提交
                </Checkbox>
                <Form
                    name="basic"
                    labelCol={{
                        span: 8,
                    }}
                    wrapperCol={{
                        span: 16,
                    }}
                    initialValues={{
                        remember: true,
                    }}
                    layout="horizontal"
                    onValuesChange={onFormLayoutChange}
                    disabled={componentDisabled}
                    onFinish={onFinish}
                    onFinishFailed={onFinishFailed}
                    autoComplete="off"
                >
                    <Form.Item
                        label="姓名"
                        name="username"
                    >
                        <Input placeholder={current.username}/>
                    </Form.Item>
    
                    <Form.Item
                        label="密码"
                        name="password"
                    >
                        <Input.Password placeholder={current.password}/>
                    </Form.Item>
                    <Form.Item
                        label="学工号"
                        name="jobnum"
                    >
                        <Input.Password placeholder={current.jobnum}/>
                    </Form.Item>
                    <Form.Item
                        label="身份"
                        name="identify"
                    >
                        <Input disabled placeholder={current.identify}/>
                    </Form.Item>
                    <Form.Item
                        label="联系方式"
                        name="phone"
                    >
                        <Input.Password placeholder={current.phone}/>
                    </Form.Item>
                    <Form.Item
                        label="电子邮件"
                        name="email"
                    >
                        <Input.Password placeholder={current.email}/>
                    </Form.Item>
                    <Form.Item
                        wrapperCol={{
                            offset: 0,
                            span: 16,
                        }}
                    >
                        <Button type="primary" htmlType="submit">
                            Submit
                        </Button>
                    </Form.Item>
                </Form>
            </>
        );
    };
    return (
        <div>
            <div className="selfInfo-head">
                <IconToFirstPage />
                <div className='selfInfo-title'><span>个人信息管理</span></div>
            </div>
            <div className="selfInfo-body">
                <FormDisabledDemo />
            </div>
            <div className="selfInfo-footer">
                <Button type="primary" htmlType="submit" onClick={()=>toDeleteSelf()}>
                    注销登录
                </Button>
                <Button type="primary" htmlType="submit" onClick={()=>toExit()}>
                    退出登录
                </Button>
            </div>
        </div>
    )
}

 

 

总体项目总结

图书订阅管理系统用时17号到今天29号,共计用时12天时间,从需求分析功能设计开始,我经历了如下几个阶段

  1. 首先是后台服务器的搭建以及连接数据库的时候出现了很多问题,我都在之前做了总结,提出数据库单独放出来,解决使用时还没创建好的问题
  2. 其次是路由层级与页面组件的继承问题,这个问题不解决,我就只能写个登陆注册了,刚开始不懂这个过程,后来搜集资料、看视频,从别人的言语缝隙中搜索自己想要的信息,那就是页面的样式继承直接受路由层级控制。
  3. 最后就是页面信息传递、PubSub订阅发布、useEffect监听,都一度让我头疼,目前我知道的是,发布订阅需要是同一页面内的组件,一个组件订阅定一个消息时,他自己对于发布消息的组件来说不能刷新,一旦刷新就拿不到数据(在去除副作用的时候),另外,不是到为什么useEffect的第二参数,在监听的时候所谓的刷新到底指的什么,因为我在实际做的时候,不管第二参数是啥,他都在执行。
  4. 这个项目的目前只是针对375*667的尺寸做的,没有适配所有尺寸的屏,使用者可以通过谷歌的后台开发工具(F12)选择手机iphone6、7、8,进一步修改别的样式,就样子来说,表格做的有亿点丑,我做了两遍功能测试,一切正常。
  5. 最后,我将自己实践useEffect以及redux,项目就到这里了,代码我找时间上传到github,已上传https://github.com/qqqq123456qqqq/reactBookSubSys
  6. 欢迎交流
posted @ 2022-08-29 21:49  乔十六  阅读(228)  评论(0编辑  收藏  举报