怎样建设网站是什么样的,网站的软文 怎么做推广,泉州科技云网站建设,公司小程序开发哪家好一、登录功能 首先要使用antd#xff0c;要先下载
yarn add antd 登录页面关键代码
import React from react
/*1、如果要在react中完成样式隔离#xff0c;需要如下操作1#xff09;命名一个xx.module.scss webpack要求2) 在需要的组件中通过ES6方式进行导入#x…一、登录功能 首先要使用antd要先下载
yarn add antd 登录页面关键代码
import React from react
/*1、如果要在react中完成样式隔离需要如下操作1命名一个xx.module.scss webpack要求2) 在需要的组件中通过ES6方式进行导入导入的格式如下import 模块名 from xx.module.scss的路径3) 在页面的标签中引用,引用的格式标签名 className{模块名.类样式名称}/或者className{模块名[类样式名称]}/
*/
/*2.antd中Form组件的使用2.1 触发Form中的onFinish事件的回调函数它的的条件1必须让Button的类型是submit,具体的做法是Button htmlTypesubmit2) 如何获取表单中文本框或者密码中的数据需要在Form.Item设置name属性
*/
import loginStyle from ../assets/css/login.module.scss
import {Form,Input,Button,message} from antd
import {useNavigate} from react-router-dom
import api from ../api
export default function Login() {const [messageApi,contextHolder]message.useMessage()const navuseNavigate()const loginasync values{const {code,message,token}await api.users.login(values)if(code){messageApi.open({type:success,content:message})//保存token到localStorage中localStorage.setItem(token,token)//跳转到后台首页nav(/home)}else{messageApi.open({type: error,content: 用户名或者密码有误,});}}return (
div{contextHolder}div className{loginStyle.container}div className{loginStyle[login-box]}Form onFinish{login}Form.Item nameusernamerules{[{required:true,message:账号不能为空}]}className{loginStyle.item}Input className{loginStyle.txt}/Input/Form.ItemForm.Item namepasswordrules{[{required:true,message:密码不能为空}]}Input.Password/Input.Password/Form.ItemForm.Item className{loginStyle.item}Button typeprimary htmlTypesubmit className{loginStyle.loginBtn}登录/Button/Form.Item/Form/div/div/div)
}
二、后台页面设计
import React,{useState,useEffect} from react
import homeStyle from ../assets/css/home.module.scss
import {Layout,Menu} from antd
import {WindowsOutlined,TrademarkCircleOutlined,UserOutlined} from ant-design/icons
import {useNavigate,Outlet} from react-router-dom
const {Header,Sider,Content,Footer}Layout
export default function Home() {const [menuList,setMenuList]useState([])const navuseNavigate()useEffect((){const list[{key:sub1,label:日常业务,icon:WindowsOutlined /,children:[{label:学员管理,key:/home/students},{label:班级管理,key:/home/classes}]},{key:sub2,label:校区管理,icon:TrademarkCircleOutlined /,children:[{label:班主任管理,key:/home/directors},{label:专业管理,key:/home/subjects}]},{key:sub3,label:系统管理,icon:UserOutlined /,children:[{key:/home/users,label:用户管理}]}]setMenuList(list)},[])const go(item){nav(item.key)}return (LayoutHeaderdiv className{homeStyle.logo}蜗牛BOSS管理系统/div/Header Layout style{{height:750px}}SiderMenu items{menuList} onClick{go}modeinlinethemedarkdefaultOpenKeys{[sub1,sub2]}defaultSelectedKeys{[/home/students]}/Menu/SiderContent{/* 设置子路由出口 */}Outlet/Outlet/Content/LayoutFooter style{{ textAlign: center}}Ant Design ©2023 Created by Ant UED/Footer/Layout /)
}
三、用户列表
import React, { useState, useEffect } from react
import { Card, Table, Avatar, Button, Space, Popconfirm } from antd;
import api from ../api
export default function Users() {const [list, setList] useState([])const columns [{title: 用户名,dataIndex: username},{title: 邮箱,dataIndex: email},{title: 手机,dataIndex: phone},{title: 角色,dataIndex: auth,render: (item) {return item 1 ? 超级管理员 : item 2 ? 普通管理员 : 暂无}},{title: 头像,dataIndex: image,render: (item) {return Avatar shapesquare size{64} src{item} /}},{title: 操作,key: action,render: (arg1) {return (SpaceButton typeprimary查看/ButtonPopconfirmplacementtoptitle提示description您确定要删除吗?onConfirm{(){deleteUser(arg1._id)}}okText确认cancelText取消Button typeprimary danger删除/Button/Popconfirm/Space)}}
]useEffect(() {getUsers()}, [])const getUsers async () {const result await api.users.getUsers()setList(result.data.result)}
const deleteUser (_id) {console.log(_id, _id);}return (div style{{ display: flex, justifyContent: center }}Card bordered{true} style{{ width: 98%, marginTop: 10px }}Table dataSource{list} columns{columns} rowKey_id/Table/Card/div)
}
四、动态菜单 在api/modules/users下编写获取权限菜单的接口
import request from ../../utils/request
export default{getAuthMenus:()request.get(/menus/getAuthMenus)
} 在SysMenus.jsx中调用getAuthMenus接口来完成权限菜单数据的获取 useEffect((){getAuthMenus()},[])const getAuthMenusasync(){const resultawait api.users.getAuthMenus()console.log(result.data);const rlisttransformDataToMenus(result.data)console.log(转换后的结果,rlist);setMenuList(rlist)} 将后台的权限菜单数据转成antd格式的菜单数据
/*** 将后台的权限菜单数据转成antd格式的菜单数据*/const transformDataToMenus(list){return list.map(item{let menuItem{label:item.title,key:item.path,icon:React.createElement(icons[item.icon])}if(item.children){menuItem.childrentransformDataToMenus(item.children)}return menuItem})} 渲染导航列表
Menuitems{menuList}modeinlinethemedarkonClick{goNav}/Menu
五、路由鉴权 在components文件夹下创建函数Auth组件 在router/index.js的路由配置中使用Auth将Home包裹起来 关键代码如下
import React,{useEffect} from react
import {Navigate,useNavigate} from react-router-dom
import api from ../api
import {message} from antd
export default function Auth({children}) {//从localStorage获取token//如何将结果转成boolean类型const navuseNavigate()const isAuth!!localStorage.getItem(token)useEffect((){getUserInfo()},[])const getUserInfoasync(){try {await api.users.getUserInfo()} catch (error) {message.warning(您的token已失效请重新登录)nav(/login)}}if(isAuth){return ({children}/)}else{message.warning(您还没有登录请登录)return (Navigate to{/login}/Navigate/)}
}
注意需要在request.js的响应拦截器中完成Promise.reject()
axios.interceptors.response.use(response{return response.data
},error{return Promise.reject(error)
})
六、分页操作
import React, { useState, useEffect } from react
import { Card, Table, Avatar, Button, Space, Popconfirm,Pagination } from antd;
import api from ../../api
export default function Users() {const [list, setList] useState([])const [total,setTotal]useState(0)const [pageSize,setPageSize]useState(10)const [current,setCurrent]useState(1)const columns [{title: 用户名,dataIndex: username},{title: 邮箱,dataIndex: email},{title: 手机,dataIndex: phone},{title: 角色,dataIndex: auth,render: (item) {return item 1 ? 超级管理员 : item 2 ? 普通管理员 : 暂无}},{title: 头像,dataIndex: image,render: (item) {return Avatar shapesquare size{64} src{item} /}},{title: 操作,key: action,render: (arg1) {return (SpaceButton typeprimary查看/ButtonPopconfirmplacementtoptitle提示description您确定要删除吗?onConfirm{(){deleteUser(arg1._id)}}okText确认cancelText取消Button typeprimary danger删除/Button/Popconfirm/Space)}}]useEffect(() {getUsers()}, [])const getUsers async (params{pageSize:10,currentPage:1}) {const result await api.users.getUsers(params)setList(result.data.result)setTotal(result.data.total)}const deleteUser (_id) {console.log(_id, _id);}const onChange(page,pageSize){let params{pageSize,currentPage:page}getUsers(params)setCurrent(page)setPageSize(pageSize)}const onSizeChange(current,pageSize){console.log(pageSize,pageSize);console.log(current,current);let params{pageSize,currentPage:current}getUsers(params)}return (div style{{ display: flex, justifyContent: center }}Card bordered{true} style{{ width: 98%, marginTop: 10px }}Table dataSource{list} columns{columns} rowKey_idpagination{false}/TablePagination style{{marginTop:20px}}total{total}pageSize{pageSize}current{current}showSizeChanger{true}pageSizeOptions{[3,5,10,15,20]}onChange{onChange}onShowSizeChange{onSizeChange}/Pagination/Card/div)
}
七、面包屑
import React,{useMemo,useEffect,useState} from react
import { Breadcrumb } from antd;
import {useLocation} from react-router-dom
import api from ../api
export default function MyBreadcrumb() {const locationuseLocation()let pathnamelocation.pathnameconst [breadcrumbAry,setBreadcrumbAry]useState([])useEffect((){getAuthMenu()},[])const getAuthMenuasync(){const resultawait api.users.getAuthMenus()transformAry(result.data)}const transformAry(list){let breadcrumbData{}list.forEach(item{if(item.children){item.children.forEach(subItem{breadcrumbData[subItem.path][item,subItem]})}})setBreadcrumbAry(breadcrumbData[pathname])}return (Breadcrumb{!breadcrumbAry?[].map((item,index)Breadcrumb.Item key{index}{item.title}/Breadcrumb.Item):breadcrumbAry.map((item,index)Breadcrumb.Item key{index}{item.title}/Breadcrumb.Item)}/Breadcrumb/)
}
八、增加操作
import React,{useEffect,useState} from react
import MyBreadcrumb from ../../components/MyBreadcrumb;
import {Button,Card,Modal,Form, Input, Select,Upload,Radio} from antd
import { PlusOutlined,LoadingOutlined } from ant-design/icons;
import api from ../../apiexport default function StudentList() {const [addForm]Form.useForm()const [classesOptions,setClassesOptions]useState([])const [subjectsOptions,setSubjectsOptions]useState([])const [loading, setLoading] useState(false);const [imageUrl, setImageUrl] useState();useEffect((){getAllSubjects()},[])const getAllSubjectsasync(){const resultawait api.subjects.getSubjects()setSubjectsOptions(result.data.result)}const changeSubjectasync(arg){const resultawait api.classes.getClassesBySubjectsId(arg)setClassesOptions(result.data.result)}const handleChange (info) {if (info.file.status uploading) {setLoading(true);return;}if (info.file.status done) {setLoading(false);setImageUrl(http://www.zhaijizhe.cn:3005/${info.file.response.data[0]})}}const uploadButton (div{loading ? LoadingOutlined / : PlusOutlined /}divstyle{{marginTop: 8,}}上传头像/div/div);const [isModalOpen, setIsModalOpen] useState(false);const showModal () {setIsModalOpen(true);};const handleOk () {setIsModalOpen(false);const params{name:addForm.getFieldValue([name]),age:addForm.getFieldValue([age]),gender:addForm.getFieldValue([gender])?addForm.getFieldValue([gender]):男,subjectsId:addForm.getFieldValue([subjectsId]),classesId:addForm.getFieldValue([classesId]),}if(addForm.getFieldValue([imagePath]).file.response){params.imageUrlhttp://www.zhaijizhe.cn:3005${addForm.getFieldValue([imagePath]).file.response.data[0]}}console.log(params,params);};const handleCancel () {setIsModalOpen(false);};return (div MyBreadcrumb/MyBreadcrumbCardButton typeprimary onClick{showModal}添加学生/ButtonModal title添加学生 open{isModalOpen} onOk{handleOk} onCancel{handleCancel} cancelText取消 okText确定Form form{addForm}Form.Item label姓名 namenameInput/Input/Form.ItemForm.Item label年龄 nameageInput/Input/Form.ItemForm.Item label性别 namegenderRadio.Group nameradiogroup defaultValue{男}Radio value{男}男/RadioRadio value{女}女/Radio/Radio.Group/Form.ItemForm.Item label专业 namesubjectsIdSelect options{subjectsOptions} fieldNames{{label:name,value:_id}}onChange{changeSubject}/Select/Form.ItemForm.Item label专业 nameclassesIdSelect options{classesOptions} fieldNames{{label:name,value:_id}}/Select/Form.ItemForm.Item label头像 nameimagePathUploadnamefilelistTypepicture-cardshowUploadList{false}onChange{handleChange}actionhttp://www.zhaijizhe.cn:3005/images/uploadImages{imageUrl ? (imgsrc{imageUrl}altavatarstyle{{width: 100%,}}/) : (uploadButton)}/Upload/Form.Item/Form/Modal/Card/div)
}