# hotel **Repository Path**: weimomolin/hotel ## Basic Information - **Project Name**: hotel - **Description**: 基于react+typescript的酒店预定移动端项目 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2023-11-30 - **Last Updated**: 2023-12-07 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # React + Thinkphp5 +Ts 酒店房间预定系统 ## 项目介绍 基于React + thinkphp5 + TypeScript 技术 UI框架:[ant](https://mobile.ant.design/) - 移动端版本 craco 插件 修改wepback配置 规避 eject 的缺点 关闭 Eslint 代码检查(语法规范的警告) 使用 react-router-dom 管理路由 ***一级二级路由划分*** BrowserRouter HashRouter 路由模式 Link NavLink 路由跳转 Outlet 匹配子级路由页面 类似vue中的```````` **axios** 接口请求 **react-cookie** 路由守卫 React城市地区插件 (地区三级选择组件) ## 项目插件配置 ### craco 插件配置 >安装:npm install @craco/craco -S >修改命令配置文件 (package.json) ```` "scripts": { "start": "craco start", "build": "craco build", "test": "craco test", "eject": "react-scripts eject" }, ```` > 项目根目录下创建配置文件 (my-app/craco.config.js) ```` /* craco.config.js */ const path = require('path') module.exports = { webpack: { // 别名 alias: { "@": path.resolve("src"), } }, //配置代理解决跨域 devServer: { proxy: { "/api": { target: "http://www.ask.com/api", changeOrigin: true, pathRewrite: { "^/api": "" } } } } } ```` ### Eslint代码检查配置 > package.json ```` "eslintConfig": { "rules": { "no-undef": "off", "no-restricted-globals": "off", "no-unused-vars": "off", "eqeqeq": "off", "no-useless-constructor": "off", "jsx-a11y/alt-text": "off" }, }, ```` ### 路由配置 > npm安装 ```` npm install react-router-dom ```` > 基本结构 ```` {/* 默认首页 */} }> {/* 路由嵌套 */} }> }> }> }> }> }> }> }> }> {/* 参数传递与接收 */} }> {/* 多个参数 */} }> {/* query传参 */} }> ```` ### axios请求封装 > src/services/request.js ```` //引入axios异步请求插件 import axios from 'axios' let cancel ,promiseArr = {} const CancelToken = axios.CancelToken; //请求拦截器 axios.interceptors.request.use(config => { //发起请求时,取消掉当前正在进行的相同请求 if (promiseArr[config.url]) { promiseArr[config.url]('操作取消') promiseArr[config.url] = cancel } else { promiseArr[config.url] = cancel } return config }, error => { return Promise.reject(error) }) //响应拦截器即异常处理 axios.interceptors.response.use( response => { // return response return response.data }, err => { if (err && err.response) { switch (err.response.status) { case 400: err.message = '错误请求' break; case 401: err.message = '未授权,请重新登录' break; case 403: err.message = '拒绝访问' break; case 404: err.message = '请求错误,未找到该资源' break; case 405: err.message = '请求方法未允许' break; case 408: err.message = '请求超时' break; case 500: err.message = '服务器端出错' break; case 501: err.message = '网络未实现' break; case 502: err.message = '网络错误' break; case 503: err.message = '服务不可用' break; case 504: err.message = '网络超时' break; case 505: err.message = 'http版本不支持该请求' break; default: err.message = `连接错误${err.response.status}` } } else { err.message = "连接到服务器失败" } console.log(err.message) return Promise.resolve(err.response) } ) //请求的默认前缀 只要是发出去请求就会 默认带上这个前缀 axios.defaults.baseURL = '/shop' //设置默认请求头 异步的 axios.defaults.headers = { 'X-Requested-With': 'XMLHttpRequest' } //设置超时请求时间 axios.defaults.timeout = 10000 //get请求 let GET = (data = {}) => { return new Promise((resolve,reject) => { axios({ method: 'get', url:data.url, params: data.params, cancelToken: new CancelToken(c => { cancel = c }) }).then(res => { resolve(res) }) }) } //post请求 let POST = (data = {}) => { return new Promise((resolve,reject) => { axios({ method: 'post', url:data.url, data:data.params, cancelToken: new CancelToken(c => { cancel = c }) }).then(res => { resolve(res) }) }) } // 文件上传请求 let UPLOAD = (data = {}) => { //封装表单数据对象 var RequestData = new FormData() if(JSON.stringify(data.params) != "{}") { for(var key in data.params) { RequestData.append(key, data.params[key]) } } return new Promise((resolve,reject) => { axios({ method: 'post', url:data.url, data:RequestData, headers:{'Content-Type': 'multipart/form-data'}, cancelToken: new CancelToken(c => { cancel = c }) }).then(res => { resolve(res) }) }) } let request = { GET, POST, UPLOAD } export default request ```` > 定义全局API变量 src/index.js ```` //引入接口请求 import request from '@/services/request.js' //设置为全局变量 React.$HTTP = request ```` ### 路由守卫配置 > 安装 ```` react-cookies -S ```` > src/routers/auth.js 定义路由验证文件 ```` import React from 'react' import {useNavigate} from 'react-router-dom' import cookie from 'react-cookies' class AuthRouter extends React.Component{ constructor(props) { super(props) this.state = {} } render() { const AuthLogin = () => { let navigate = useNavigate() React.useEffect(() => { var LoginUser = cookie.load('LoginUser') ? cookie.load('LoginUser') : {} if(JSON.stringify(LoginUser) === "{}") { navigate('/user/base/login') } }) return false } return ( <> { this.props.auth && } {this.props.component} ) } } export default AuthRouter ```` > 在路由入口封装文件中的使用方式 /src/routers/index.js ```` import React from 'react' import {Routes, Route, Outlet} from 'react-router-dom' import AuthRouter from './auth' import Home from '@/components/home.js' // 引入每个目录下面的index.js文件 const ModulesFile = require.context('./',true,/index.js$/) // 总路由集合 const RouterMap = [] //对引入的文件进行循环 ModulesFile.keys().reduce((modules, modulePath) => { // 路由模块名称 文件夹/index user/index const ModuleName = modulePath.replace(/^.\/(.*)\.js/,'$1') //不包含当前index.js 文件 if(ModuleName !== 'index') { //路由列表 const ModuleList = ModulesFile(modulePath) //追加到数组 RouterMap.push(...ModuleList.default) } return RouterMap }, {}) class RouterList extends React.Component{ constructor(props) { super(props) this.state = {} } render() { return ( <> {/* 默认首页 */} }> }> { RouterMap.map((item, index) => { return ( }>}> {item.children && item.children.map((son, idx) => }>}>) } ) }) } ) } } export default RouterList ```` > 路由中使用 ```` import AuthRouter from './auth' {/* 默认首页 */} }> { }>} > } ```` ```` /** * 用户基本资料路由 - 子路由 */ const base = [ { path: "base/profile", name: 'profile', component: profile, auth: true // true 访问此界面需要通过路由守卫验证 } ] export default base ```` ## 难点记录(BUG记录) ### tp5.0使用$this->request->param()获取参数时,多增加了路由地址参数 [csdn 修改伪静态文件解决办法](https://blog.csdn.net/admin_web/article/details/114835485?spm=1001.2101.3001.6650.16&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-16-114835485-blog-108408620.235%5Ev39%5Epc_relevant_anti_t3&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-16-114835485-blog-108408620.235%5Ev39%5Epc_relevant_anti_t3&utm_relevant_index=21). 修改模型文件解决办法(添加过滤器) ````