react图书商城前后端

发布时间 2023-08-01 10:37:51作者: 晚安圆圆

下载:axios antd-mobile antd-mobile-icons sass

连接mongodb:

const mongoose = require("mongoose")
mongoose.connect('mongodb://127.0.0.1:27017/zg5_zk3_2204_express',(err)=>{
    if(!err){
        console.log('连接成功!');
    }
})
module.exports=mongoose

创建表模型:

const mongoose = require("./db")
var Schema = mongoose.Schema
 
// 图书
var bookSchema = new Schema({
    bookName:String,
    img:String,
    // 判断是否在书架里: false没在书架,true在书架
    state:{
        type:Boolean,
        default:false
    },
    // 判断是否看完:false正在看,true已完结
    bookState:{
        type:Boolean,
        default:false
    }
})
var bookModel = mongoose.model("Book",bookSchema)
 
// 用户
var userSchema = new Schema({
    mobile:String,
    passWord:String
})
var userModel = mongoose.model("User",userSchema)
 
module.exports = { bookModel,userModel }

后端接口:

// 登录时添加用户
router.post("/user/add",async (req,res)=>{
  var data = req.body
  await userModel.create(data)
  res.send({
    token:data.mobile
  })
})
 
 
// shop路由及book路由图书展示
router.get("/book/list",async (req,res)=>{
  var data
  if(!req.query.search){
    data =  await bookModel.find()
  }else{
    data =  await bookModel.find({bookName:req.query.search})
 
  }
  res.send({
    data
  })
})
 
// shop路由的图书添加
router.post("/book/add",async (req,res)=>{
  let data = req.body._id
  await bookModel.updateOne({_id:data},{state:true})
  res.send({})
 
})
 
// bookState状态的更改
router.post("/bookState/update",async (req,res)=>{
  let data = req.body
  await bookModel.updateOne({_id:data._id},{bookState:data.bookState})
  res.send({})
})
 
// state状态的更改
router.post("/state/update",async (req,res)=>{
  let data = req.body
  await bookModel.updateOne({_id:data._id},{state:false})
  res.send({})
})

前端登录页面:

import React, { useState } from 'react'
import { Form, Input, Button } from 'antd-mobile'
import styles from './demo2.less'
import { CloseOutline, CheckOutline } from 'antd-mobile-icons'
import { history } from 'umi'
import axios from 'axios'
 
export default function Login() {
    /** 切换主题 */
 
    // 存储颜色列表
    const back = ["black","red", "blue", "green"]
    const [backIndex, setBackIndex] = useState(0)
    // 切换主题
    let backClick = () => {
        let backindex = backIndex
        if (backindex >= back.length - 1) {
            setBackIndex(0)
        } else {
            backindex += 1
            setBackIndex(backindex)
        }
    }
    /** 手机号 */
 
    // 存储手机号,用于校验
    const [mobile, setMobile] = useState("")
    // 手机号的change事件
    let onMobileChange = (value) => {
        setMobile(value)
    }
    // 手机号的校验
    const phone = /^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/
 
    /** 密码 */
 
    // 存储密码,用于校验
    const [passWord, setPassWord] = useState("")
    // 密码的change事件
    let onPassWordChange = (value: any) => {
        setPassWord(value)
    }
    // 密码的校验
    const pwd = /^[a-zA-Z][a-zA-Z0-9]{5}$/
 
    /** 点击登录 */
    let onLoginClick = () => {
        axios.post("http://localhost:3000/user/add", { mobile: mobile, passWord: passWord }).then(value => {
            window.localStorage.setItem("token", value.data.token)
            history.push({ pathname: "/shop" })
        })
    }
    return (
        <div>
            <h1 style={{ height: "60px", width: "100%", color: "white", textAlign: "center", fontSize: "24px", lineHeight: "60px", backgroundColor: back[backIndex] }}>用户登录 <b onClick={backClick} style={{ fontSize: "12px", float: "right", lineHeight: "60px", color: "white" }}>切换主题</b> </h1>
            <div>
                <Form style={{ marginTop: "150px" }} layout='horizontal'>
                    <Form.Item
                        label='手机号码'
                        extra={
                            <div className={styles.extraPart}>
                                {phone.test(mobile) ? <CheckOutline style={{ background: "green", border: "none", borderRadius: "50%", color: "white" }} /> : <CloseOutline style={{ background: "red", border: "none", borderRadius: "50%", color: "white" }} />}
                            </div>
                        }
                    >
                        <Input onChange={onMobileChange} placeholder='请输入手机号码' clearable />
                    </Form.Item>
                    <Form.Item
                        label='密码'
                        extra={
                            <div className={styles.extraPart}>
                                {pwd.test(passWord) ? <CheckOutline style={{ background: "green", border: "none", borderRadius: "50%", color: "white" }} /> : <CloseOutline style={{ background: "red", border: "none", borderRadius: "50%", color: "white" }} />}
                            </div>
                        }
                    >
                        <Input onChange={onPassWordChange} placeholder='请输入密码' clearable />
                    </Form.Item>
                    <Button onClick={onLoginClick} disabled={pwd.test(passWord) && phone.test(mobile) ? false : true} style={{ border: "none", background: back[backIndex], marginTop: "50px" }} block type='submit' color='primary' size='large'>
                        登录
                    </Button>
                </Form>
 
            </div>
 
 
        </div>
    )
}

css样式:scss格式

.extraPart {
    border-left: solid 1px #eeeeee;
    padding-left: 12px;
    font-size: 17px;
    line-height: 22px;
  }
  .eye {
    padding: 4px;
    cursor: pointer;
    svg {
      display: block;
      font-size: var(--adm-font-size-7);
    }
  }

图书商城:

import React, { useEffect, useState } from 'react'
import { Input,Toast  } from 'antd-mobile'
import { CloseOutline, CheckOutline,AddOutline } from 'antd-mobile-icons'
import axios from 'axios'
import { history } from 'umi'
export default function Shop() {
    const [inputValue,setInputValue] = useState("")
    const [data,setData] = useState([])
    let getBookList = (value:any) =>{
        axios.get("http://localhost:3000/book/list?search="+value).then(value=>{
            setData(value.data.data);
        })
    }
    let onInputChange = (value:any) =>{
        setInputValue(value)
        getBookList(value)
    }
    // 添加图书到书架
    let addBook = (item:any) =>{
        if(item.state){
            Toast.show({
                content: '书架中已有此书',
                duration: 1000,
              })
        }else{
            axios.post("http://localhost:3000/book/add",{_id:item._id}).then(value=>{
                getBookList(inputValue)
                Toast.show({
                    content: '加入成功',
                    duration: 1000,
                  })
            })
        }
        
    }
 
    useEffect(()=>{
        getBookList(inputValue)
    },[])
    return (
        <div>
            <h1  style={{ position:"sticky",top:"0",left:"0", height: "60px", width: "100%", color: "white", textAlign: "center", fontSize: "24px", lineHeight: "60px", backgroundColor: "red" }}>图书商城 <b onClick={() => { history.push({pathname:"/book"}) }} style={{ fontSize: "12px", float: "right", lineHeight: "60px", color: "white" }}>我的书架</b> </h1>
            <div>
                <Input onChange={onInputChange} style={{ border:"1px solid red",marginTop:"-5px" }} placeholder='请输入书名搜索' />
                <div>
                    {
                        data.map((item, index) => {
                            return (<div key={item.bookName} style={{ marginBottom:"5px",border:"1px solid black", float: index%2==0 ? "left":"right",  width: "45%", display: "inline-block" }}>
                                <img style={{ marginBottom:"15px",height:"200px",width: "100%" }} src={require("../images/" + item.img)} alt="" />
                                <p style={{ color:'red' }}>{item.bookName} <AddOutline onClick={()=>{addBook(item)}} style={{ float:"right",marginRight:"10px", color:"white",backgroundColor:"red",border:"none",borderRadius:"50%" }} /></p>
                            </div>)
                        })
                    }
                </div>
            </div>
        </div>
    )
}

书架:

import React, { useState, useEffect } from 'react'
import { NavBar, Collapse } from 'antd-mobile'
import axios from 'axios'
import { history } from 'umi'
 
export default function Book() {
    const [data, setData] = useState([])
    const back = () => {
        history.push({pathname:"/shop"})
    }
 
    useEffect(() => {
        axios.get("http://localhost:3000/book/list").then(value => {
            setData(value.data.data);
        })
    }, [])
 
    let onLeftClick = (id, state) => {
        axios.post("http://localhost:3000/bookState/update", { _id: id, bookState: state }).then(value => {
            axios.get("http://localhost:3000/book/list").then(value => {
                setData(value.data.data);
            })
        })
    }
    let onRightClick = (id) => {
        axios.post("http://localhost:3000/state/update", { _id: id }).then(value => {
            axios.get("http://localhost:3000/book/list").then(value => {
                setData(value.data.data);
            })
        })
    }
    return (
        <div>
            <NavBar style={{ color: "white", textAlign: "center", fontSize: "24px", lineHeight: "60px", backgroundColor: "red" }} onBack={back}>图书商城 </NavBar>
            <div>
                <Collapse>
                    <Collapse.Panel key='1' title='正在看'>
                        <ul style={{ listStyle: "none" }}>
                            {
                                data.filter(item => { return !item.bookState && item.state }).length >0?
                                data.filter(item => { return !item.bookState && item.state }).map(item => {
                                    return (
                                        <li key={item.bookName} style={{ marginBottom: "7px" }}>
                                            <b style={{ color: "black" }}>{item.bookName}</b>
                                            <div style={{ float: "right" }}>
                                                <span onClick={() => { onLeftClick(item._id, true) }} style={{ color: "red" }}>标记为已看完  |</span>
                                                <span onClick={() => { onRightClick(item._id) }}>  删除图书</span>
                                            </div>
                                        </li>
                                    )
                                }): <li>没有正在看的图书</li>
                            }
                        </ul>
                    </Collapse.Panel>
                    <Collapse.Panel key='2' title='已完结'>
                        <ul style={{ listStyle: "none" }}>
                            {   data.filter(item => { return item.bookState && item.state }).length >0?
                                data.filter(item => { return item.bookState && item.state }).map(item => {
                                    return (
                                        <li key={item.bookName} style={{ marginBottom: "7px" }}>
                                            <b style={{ color: "black" }}>{item.bookName}</b>
                                            <div style={{ float: "right" }}>
                                                <span onClick={() => { onLeftClick(item._id, false) }} style={{ color: "red" }}>再看一遍  |</span>
                                                <span onClick={() => { onRightClick(item._id) }}>  删除图书</span>
                                            </div>
                                        </li>
                                    )
                                }): <li>没有看完的图书</li>
                            }
                        </ul>
                    </Collapse.Panel>
                </Collapse>
            </div>
        </div>
    )
}