express:下载 mongoose 7版本 +配置cors
1:创建module文件夹(db.js、module.js)
连接mongodb数据库:
const mongoose = require("mongoose") mongoose.connect("mongodb://127.0.0.1:27017/zg6_zk3_2204_koa").then(()=>{ console.log("连接成功"); }) module.exports = mongoose
创建表结构:
const mongoose = require("./db") let Schema = mongoose.Schema var userSchema = new Schema({ userName:String, mobile:String, birth:String, duration:String, sex:String, xueli:String, positionList:Array, tagList:Array, }) var userModel = mongoose.model("user",userSchema) // userModel.create({ // userName:"行行行", // mobile:"15738781657", // birth:"2001-08-28", // duration:"2020-09-07", // sex:"女", // xueli:"专科", // positionList:["前端开发工程师","全栈开发工程师"], // tagList:[ // { // tag:"前端", // state:false // }, // { // tag:"全栈", // state:true // } // ] // }) module.exports = { userModel }
后端接口:
const router = require('koa-router')() const { userModel } = require("../model/model") router.get('/basic', async (ctx, next) => { let data = await userModel.find({_id:"6445edd4831ac2ea7b8e8c07"}) let list = data[0] ctx.body = { basicMsg:{ _id: list._id, userName: list.userName, mobile: list.mobile, birth: list.birth, duration: list.duration, sex: list.sex, xueli: list.xueli, }, positionList: list.positionList, tagList: list.tagList, } }) router.post('/update', async (ctx, next) => { let data = ctx.request.body await userModel.updateOne({_id:data._id},data) ctx.body = {code:200,msg:"修改成功"} }) router.post('/update/two', async (ctx, next) => { let data = ctx.request.body await userModel.updateOne({_id:"6445edd4831ac2ea7b8e8c07"},{positionList:data}) ctx.body = {code:200,msg:"修改成功"} }) router.post('/update/tag', async (ctx, next) => { let data = ctx.request.body await userModel.updateOne({_id:"6445edd4831ac2ea7b8e8c07"},{tagList:data}) ctx.body = {code:200,msg:"修改成功"} }) module.exports = router
前端:
编辑简历:
import React, { useEffect, useState } from 'react' import { Tag, Input, DatePicker, Select, Radio, Button, Progress } from 'antd'; import { CheckCircleFilled } from '@ant-design/icons'; import axios from 'axios' import dayjs from 'dayjs'; import { history } from 'umi' export default function index() { /** 基本信息 */ const [basicState, setBasicState] = useState(true) const [basicMsg, setBasicMsg] = useState({}) const [basicUpdateMsg, setBasicUpdateMsg] = useState({}) // 姓名的改变 let onNameInputChange = (e) => { let obj = { ...basicUpdateMsg } // console.log(basicMsg.keys().length); obj.userName = e.target.value setBasicUpdateMsg(obj); } // 出生日期的改变 let onBirthChange = (date: any, dateString: any) => { let obj = { ...basicUpdateMsg } obj.birth = dateString setBasicUpdateMsg(obj); }; // 开始工作时间的改变 let onDurationChange = (date: any, dateString: any) => { let obj = { ...basicUpdateMsg } obj.duration = dateString setBasicUpdateMsg(obj); }; // 性别的改变 let onSexChange = (e: any) => { let obj = { ...basicUpdateMsg } obj.sex = e.target.value setBasicUpdateMsg(obj); } // 学历的改变 let onXueliSelectChange = (value) => { let obj = { ...basicUpdateMsg } obj.xueli = value setBasicUpdateMsg(obj); } // 手机号的改变 let onMobileInputChange = (e) => { let obj = { ...basicUpdateMsg } obj.mobile = e.target.value setBasicUpdateMsg(obj); } // 保存Button点击事件 let onUpdateButtonClick = () => { axios.post("http://127.0.0.1:3000/update", basicUpdateMsg).then(res => { let obj = { ...basicUpdateMsg } setBasicMsg(obj) }) setBasicState(true) } // 取消Button点击事件 let onEscButtonClick = () => { let obj = { ...basicMsg } setBasicUpdateMsg(obj) setBasicState(true) } // 获取基本信息数据 let getBasic = () => { axios.get("http://127.0.0.1:3000/basic").then(res => { setBasicMsg(res.data.basicMsg); setBasicUpdateMsg(res.data.basicMsg) setPositionList(res.data.positionList) setTagList(res.data.tagList) }) } // 进入页面就获取基本信息 useEffect(() => { getBasic() }, []) /** 求职意向 */ // 求职 const [positionList, setPositionList] = useState([]) // 移入的Index const [mouseIndex, setMouseIndex] = useState() // 编辑时的Index const [updateIndex, setUpdateIndex] = useState() // 编辑时新的值 const [updateSelectValue, setUpdateSelectValue] = useState() // 编辑时Change事件 let onUpdateSelectChange = (e) => { setUpdateSelectValue(e) } // 保存Button按钮点击事件 let onSelectUpdateClick = () => { let list = [...positionList] list[updateIndex] = updateSelectValue console.log(list); axios.post("http://127.0.0.1:3000/update/two", list).then(res => { setPositionList(list) setUpdateIndex("") }) } // 添加时的状态 const [addState, setAddState] = useState(false) // 添加时的值 const [addSelectValue, setAddSelectValue] = useState("前端工程师") // 添加时Change事件 let onAddSelectChange = (e) => { setAddSelectValue(e) } // 添加时 保存按钮点击事件 let onSelectAddClick = () => { let list = [...positionList] list.push(addSelectValue) axios.post("http://127.0.0.1:3000/update/two", list).then(res => { setPositionList(list) setAddState(false) setAddSelectValue("前端工程师") }) } // 删除事件 let onDeleteClick = (index) => { let list = [...positionList] list.splice(index, 1) axios.post("http://127.0.0.1:3000/update/two", list).then(res => { setPositionList(list) }) } /** 特殊标签 */ // 存储标签的数组 let [tagList, setTagList] = useState([]) // 添加标签的状态 let [addTagState, setAddTagState] = useState(false) // 添加标签的值 let [addTagValue, setAddTagValue] = useState() // 添加标签Input的Change事件 let onAddTagInputChange = (e) => { setAddTagValue(e.target.value) } // 添加标签的点击事件 let onAddTagClick = () => { if (addTagValue) { let list = [...tagList] let obj = { tag: addTagValue, state: true } list.push(obj) axios.post("http://127.0.0.1:3000/update/tag", list).then(res => { setTagList(list) setAddTagValue("") }) } } // 添加标签的 保存/取消 按钮点击事件 let onAddTagButtonClick = () => { setAddTagState(false) setAddTagValue("") } // 将标签进行高亮 let TagClick = (index) => { let list = [...tagList] list[index].state = !list[index].state axios.post("http://127.0.0.1:3000/update/tag", list).then(res => { setTagList(list) }) } // 预览简历 let historyClick = () => { history.push("/home", { basicMsg, positionList, tagList }) } return ( <div style={{ width: "100%", height: "100%", backgroundColor: "#F3F3F3", display: "flex" }}> {/* 左侧 */} <div style={{ width: "70%", backgroundColor: "#FFF", }}> {/* 基本信息 */} <div style={{ padding: "25px" }}> <h1>基本信息 <Tag color="orange">必填</Tag></h1> {/* 展示 */} <div style={{ height: "100px", display: basicState ? "" : "none" }}> <div style={{ display: "inline-block" }}> <img style={{ width: "89px" }} src="https://img2.baidu.com/it/u=3618236253,1028428296&fm=253&app=138&size=w931&n=0&f=JPEG&fmt=auto?sec=1680886800&t=174f9f7c10fbdb55ff4de04788a63d4f" alt="" /> </div> <div style={{ display: "inline-block", marginLeft: "15px" }}> <h2 style={{ display: "inline-block" }}>{basicMsg.userName}</h2> <div><span>{basicMsg.sex}</span> <span>{dayjs(dayjs().format('YYYY-MM-DD')).diff(basicMsg.birth, 'year')}岁</span> <span>{basicMsg.xueli}</span> <span>{dayjs(dayjs().format('YYYY-MM-DD')).diff(basicMsg.duration, 'year')}年</span></div> </div> <div onClick={() => { setBasicState(false) }} style={{ display: "inline-block", float: "right", marginRight: "30px", color: "#94ABFA" }}> 编辑 </div> </div> {/* input修改 */} <div style={{ height: "300px", backgroundColor: "#FFF", display: basicState ? "none" : "" }}> {/* 左侧 */} <div style={{ height: "200px", width: "50%", float: "left" }}> <div> <div style={{ marginTop: "30px", display: "inline-block", width: "30%", textAlign: "right", marginRight: "15px" }}> * 姓名 </div> <Input onChange={onNameInputChange} value={basicUpdateMsg.userName} style={{ width: "200px", }} placeholder="请输入姓名" /> </div> <div style={{ margin: "20px 0" }}> <div style={{ display: "inline-block", width: "30%", textAlign: "right", marginRight: "15px" }}> * 出生日期 </div> <DatePicker value={dayjs(basicUpdateMsg.birth, 'YYYY-MM-DD')} format="YYYY-MM-DD" onChange={onBirthChange} placeholder="选择出生日期" /> </div><div> <div style={{ display: "inline-block", width: "30%", textAlign: "right", marginRight: "15px" }}> * 开始工作时间 </div> <DatePicker value={dayjs(basicUpdateMsg.duration, 'YYYY-MM-DD')} format="YYYY-MM-DD" onChange={onDurationChange} placeholder="选择开始工作时间" /> </div> </div> {/* 右侧 */} <div style={{ height: "200px", width: "50%", float: "right" }}> <div> <div style={{ marginTop: "30px", display: "inline-block", width: "30%", textAlign: "right", marginRight: "15px" }}> * 性别 </div> <Radio.Group onChange={onSexChange} value={basicUpdateMsg.sex}> <Radio value="男">男</Radio> <Radio value="女">女</Radio> </Radio.Group> </div> <div style={{ margin: "20px 0" }}> <div style={{ display: "inline-block", width: "30%", textAlign: "right", marginRight: "15px" }}> * 最高学历 </div> <Select value={basicUpdateMsg.xueli} style={{ width: 120 }} onChange={onXueliSelectChange} options={[ { value: '专科', label: '专科' }, { value: '本科', label: '本科' }, { value: '研究生', label: '研究生' }, { value: '硕士', label: '硕士' }, { value: '博士', label: '博士' }, ]} /> </div> <div> <div style={{ display: "inline-block", width: "30%", textAlign: "right", marginRight: "15px" }}> * 联系电话 </div> <Input onChange={onMobileInputChange} value={basicUpdateMsg.mobile} style={{ width: "200px", }} placeholder="请输入联系电话" /> </div> </div> {/* 底部Button按钮 */} <div style={{ margin: "0 auto" }}> <div style={{ textAlign: "center" }}> <Button type="primary" style={{ marginRight: "10px" }} onClick={onUpdateButtonClick}>保存</Button> <Button style={{ marginLeft: "10px" }} onClick={onEscButtonClick}>取消</Button> </div> </div> </div> </div> {/* 求职意向 */} <div style={{ padding: "25px" }}> <h1>求职意向 <Tag color="orange">必填</Tag> <div onClick={() => { setAddState(true) }} style={{ color: "#94ABFA", fontSize: "18px", float: "right", display: "inline-block" }}>+添加一条</div> </h1> {/* 展示的数据 */} <div> <ul style={{ listStyle: "none", padding: "10px 0" }}> { positionList.map((item, index) => { return ( updateIndex !== index ? <li style={{ padding: "15px 0" }} onMouseOver={() => { setMouseIndex(index) }} onMouseOut={() => { setMouseIndex(9999) }}> 职位:{item} <div style={{ float: "right", display: mouseIndex == index ? "inline-block" : "none" }}> <div onClick={() => { setUpdateIndex(index); setUpdateSelectValue(item) }} style={{ display: "inline-block", marginRight: "5px" }}> 编辑 </div> / <div onClick={() => { onDeleteClick(index) }} style={{ display: "inline-block", marginLeft: "5px" }}> 删除 </div> </div> </li> : <div> <div style={{ display: "inline-block", marginRight: "15px" }}> * 职位 </div> <Select value={updateSelectValue} style={{ width: 120 }} onChange={onUpdateSelectChange} options={[ { value: '前端工程师', label: '前端工程师' }, { value: '后端工程师', label: '后端工程师' }, { value: '前端架构师', label: '前端架构师' }, { value: '全栈工程师', label: '全栈工程师' }, { value: '算法工程师', label: '算法工程师' }, ]} /> <div style={{ padding: "10px 0", textAlign: "center" }}> <Button type="primary" style={{ marginRight: "10px" }} onClick={onSelectUpdateClick}>保存</Button> <Button style={{ marginLeft: "10px" }} onClick={() => { setUpdateIndex("") }}>取消</Button> </div> </div> ) }) } </ul> </div> {/* 添加表单 */} <div style={{ display: addState ? "" : "none" }}> <div style={{ display: "inline-block", marginRight: "15px" }}> * 职位 </div> <Select value={addSelectValue} style={{ width: 120 }} onChange={onAddSelectChange} options={[ { value: '前端工程师', label: '前端工程师' }, { value: '后端工程师', label: '后端工程师' }, { value: '前端架构师', label: '前端架构师' }, { value: '全栈工程师', label: '全栈工程师' }, { value: '算法工程师', label: '算法工程师' }, ]} /> <div style={{ padding: "10px 0", textAlign: "center" }}> <Button type="primary" style={{ marginRight: "10px" }} onClick={onSelectAddClick}>保存</Button> <Button style={{ marginLeft: "10px" }} onClick={() => { setAddState(false); setAddSelectValue("前端工程师") }}>取消</Button> </div> </div> </div> {/* 特长标签 */} <div style={{ padding: "25px" }}> <h1>特长标签 <div onClick={() => { setAddTagState(true) }} style={{ float: "right", fontSize: "18px" }}>编辑</div> </h1> <div style={{ padding: "15px 0", marginLeft: "25px", display: addTagState ? "none" : "" }}> { tagList.filter((item, index) => { return item.state }).map((item, index) => { return <Tag style={{ padding: "5px 10px", marginBottom: "5px" }} color={item.state ? "orange" : ""}>{item.tag}</Tag> }) } </div> <div style={{ display: addTagState ? "" : "none" }}> <div style={{ padding: "15px 0", marginLeft: "25px", }}> { tagList.map((item, index) => { return <Tag onClick={() => { TagClick(index) }} style={{ padding: "5px 10px", marginBottom: "5px" }} color={item.state ? "orange" : ""}>{item.tag}</Tag> }) } </div> <div> <Input value={addTagValue} onChange={onAddTagInputChange} style={{ width: "150px" }} placeholder='请输入自定义标签' /><Button onClick={onAddTagClick} >添加</Button> </div> <div style={{ padding: "10px 0", textAlign: "center" }}> <Button type="primary" style={{ marginRight: "10px" }} onClick={onAddTagButtonClick}>保存</Button> <Button style={{ marginLeft: "10px" }} onClick={onAddTagButtonClick}>取消</Button> </div> </div> </div> </div> {/* 右侧 */} <div style={{ width: "15%", backgroundColor: "#FFF", marginLeft: "25px", padding: "15px" }}> <h3>简历完整度: <span> { Math.floor((((Object.values(basicMsg).filter(item => { return item }).length == 7 ? 1 : 0) + (positionList.length > 0 ? 1 : 0) + (tagList.length > 0 ? 1 : 0)) / 7) * 100) } %</span> </h3> <Progress percent={Math.floor((((Object.values(basicMsg).filter(item => { return item }).length == 7 ? 1 : 0) + (positionList.length > 0 ? 1 : 0) + (tagList.length > 0 ? 1 : 0)) / 7) * 100)} showInfo={false} /> <ul style={{ listStyle: "none", margin: "0 auto", marginRight: "35px", fontSize: "16px" }}> <li style={{ marginBottom: "25px" }}> 基本信息 <span style={{ float: "right" }}> { Object.values(basicMsg).filter(item => { return item }).length == 7 ? <CheckCircleFilled style={{ color: "#468afc" }} /> : <span style={{ float: "right" }}>待完善</span> } </span> </li> <li style={{ marginBottom: "25px" }}> 求职状态 <span style={{ float: "right" }}>待完善</span> </li> <li style={{ marginBottom: "25px" }}> 求职意向 { positionList.length > 0 ? <CheckCircleFilled style={{ color: "#468afc", float: "right" }} /> : <span style={{ float: "right" }}>待完善</span> } </li> <li style={{ marginBottom: "25px" }}> 特长标签 { tagList.filter(item => { return item.state }).length > 0 ? <CheckCircleFilled style={{ color: "#468afc", float: "right" }} /> : <span style={{ float: "right" }}>待完善</span> } </li> <li style={{ marginBottom: "25px" }}> 自我描述 <span style={{ float: "right" }}>待完善</span> </li> <li style={{ marginBottom: "25px" }}> 教育经历 <span style={{ float: "right" }}>待完善</span> </li> <li style={{ marginBottom: "25px" }}> 工作经历 <span style={{ float: "right" }}>待完善</span> </li> </ul> <Button onClick={historyClick} type="primary" block style={{ backgroundColor: "#e2a12c", border: "1px solid #e2a12c" }}> 预览简历 </Button> </div> </div> ) }
预览简历页面:
import React, { useEffect } from 'react' import { useLocation } from 'umi' import dayjs from 'dayjs'; import { Tag, Input, DatePicker, Select, Radio, Button, Progress } from 'antd'; export default function Home() { let location = useLocation() let basicMsg = location.state.basicMsg let positionList = location.state.positionList let tagList = location.state.tagList useEffect(() => { console.log(location.state); }, []) return ( <div> <div> <h1>个人信息</h1> <div style={{ display: "inline-block" }}> <img style={{ width: "89px" }} src="https://img2.baidu.com/it/u=3618236253,1028428296&fm=253&app=138&size=w931&n=0&f=JPEG&fmt=auto?sec=1680886800&t=174f9f7c10fbdb55ff4de04788a63d4f" alt="" /> </div> <div style={{ display: "inline-block", marginLeft: "15px" }}> <h2 style={{ display: "inline-block" }}>{basicMsg.userName}</h2> <div><span>{basicMsg.sex}</span> <span>{dayjs(dayjs().format('YYYY-MM-DD')).diff(basicMsg.birth, 'year')}岁</span> <span>{basicMsg.xueli}</span> <span>{dayjs(dayjs().format('YYYY-MM-DD')).diff(basicMsg.duration, 'year')}年</span></div> </div> </div> <div> <h1>求职意向</h1> { positionList.map((item: any, index: any) => { return ( <div key={index}> 期望职位: {item} </div> ) }) } </div> <div> <h1>个性标签</h1> { tagList.filter((item, index) => { return item.state }).map((item, index) => { return <Tag style={{ padding: "5px 10px", marginBottom: "5px" }} color={item.state ? "orange" : ""}>{item.tag}</Tag> }) } </div> </div> ) }