下载: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>
)
}
浙公网安备 33010602011771号