# @peace/template_front_client
> 基于 React.18 + Vite.4 预置 Antd.5 的客户端(web)
## 简洁
本项目以核心包`@peace/react_client`封装服务内容。
以`服务端渲染(SSR)`为核心,提供日常工作所需的`变量配置`、`路由配置`、`跨平台数据请求`、`统一资源管理`、`工具函数预置`等相关内容。
## 使用
> 使用前可参阅下方 `目录结构` 了解项目结构
### 启动服务
确保 Node.js 和 npm 已安装。
```bash
npm start
```
> 建议使用 vscode 的 `运行和调试`(F5)快捷键启动服务,更可方便配置环境变量
### 项目配置
项目配置文件位于 `config.cjs` 文件,可根据实际需求进行配置。
配置内容均已在文件中预置和注释说明,可根据实际需求进行修改。
- 关键配置(*)
- vite:Vite 相关配置 https://vitejs.cn/vite5-cn/config/
- envPrefix:环境变量前缀,此前缀的环境变量将会被注入到 `window.env` 中
- server:
- alias: 别名配置(框架预置了一下别名以供调用)
- @u:工具集目录
- @comps:公共组件目录
- @assets:静态资源目录
### 功能模块编写`sections`
> 模块化设计,以功能模块为单位进行编写。
模块应该在 `client/src/sections` 目录下创建
目录结构如下:
```
模块
├── actions // Redux actions
├── components // 组件
├── container // 容器
├── index.js // 模块入口文件
└── router.js // [!]路由文件
```
#### 路由配置`router.js`
路由文件以对象形式配置,兼顾路由导航及 Menu 主菜单、面包屑等信息配置
.eg
```javascript
import { HomeOutlined, ApartmentOutlined, } from "@ant-design/icons";
import Index from "./container";
export default {
type: "inner", // 路由类型 ('inner' 出现在 layout 布局内 | 'outer' layout 布局外,内容占满页面全部)
route: {
key: "home", // 路由 key
path: "home", // 路由
component: Index, // 路由对应组件
label: "Home", // 导航栏或面包屑显示的名称
icon: , // 导航栏图标
nav: true, // 是否显示在左侧 Sider - Menu 导航栏
auth: ["admin"], // 访问权限 key
children: [ // 子路由
// { ... 重复以上配置 },
],
},
};
```
#### Redux `actions`
框架使用 Redux 进行状态管理,以 `actions` 为基础,提供 `reducer` 和 `store` 等内容。
对于数据请求内容,根据需要可编写 `action` 以存储‘状态’并使用
- 编写`action`
```javascript
// actions/auth.js
import { basicAction, apiTable } from "@u"
const login = basicAction.post('/login', {
reducerName: "user" // 存储状态的 reducer 名称
});
export default { login }
```
`basicAction` 为框架多次封装的 `action`(基于`@peace/react_client - request`,更多参数可参考相关目录),基于此方法可免于编写`reducer`
所有 `action` 需在 入口文件`index.js` 中暴露,以集中至 `state.global` 方便调用
```javascript
// actions/index.js
import actions from "./auth";
export default {
...actions
}
```
- 使用`action`
在 `container` 或 `components` 等地方使用 `action`时:
```javascript
import { useDispatch, useSelector } from "react-redux";
export default function login (){
const dispatch = useDispatch(); // 获取 dispatch
const actions = useSelector(state => state.global.actions); // 获取所有 actions
// 使用 useSelector 可以获取所有 actions 的值
dispatch(actions.login({ // 调用 action
body: {},
})).then(res => {
const { success, data } = res.payload; // 从 payload 中获取数据
/**
* success: true, // 请求是否成功
* data: {} // 请求返回的数据
*/
});
}
```
除 `dispatch(action()).then()` 获取 `action` 的返回值外,还可以以一下方式获取:
```javascript
import { useDispatch, useSelector } from "react-redux";
export default function login (){
const dispatch = useDispatch();
const actions = useSelector(state => state.global.actions);
dispatch(actions.login())
// ...
const { success, data, error, loading } = useSelector(state => state.user); // state.user 是因为 action 定义了 reducerName = "user"
// 返回值包括 success, data, error, loading
}
```
#### 组件 `components`
- 定义:
- 组件是一个 UI 逻辑的最小单位,通常专注于如何呈现内容(即外观)。
- 无状态组件(Stateless Components)较常见,它们通常只接收 props,不直接管理状态。
#### 容器 `container`
- 定义
- 容器是负责 业务逻辑和数据管理 的组件,通常连接应用的状态(如 Redux store)并将数据传递给组件。
- 容器通常管理状态、数据流、API 调用等复杂逻辑。
#### 模块入口`index.js`
模块入口文件需暴露指定内容以便于`Layout`进行渲染
```javascript
import route from './router'
import actions from './actions'
export default {
route: route,
actions: actions,
}
```
#### 模块使用
模块内容需在 `client/src/app.jsx` 中引用并挂载至 `Layout` 组件
```javascript
// ...
import Auth from "./sections/auth";
// ...
```
### 工具集 `utils`
工具集在 `client/src/utils` 目录下;
工具集内提供了一些常用的工具函数,如 `api.js`、`parseProcessData.js` 等。
- `api.js`:提供了 api 路由 map,可根据实际需求进行配置并多处使用;一般 action 中建议直接写入 api 路由,以方便管理。
- `parseProcessData.js`:提供了项企表单数据解析能力。
- `index.js`:工具集入口文件,暴露所有工具函数。
- `apiRequest`: 在入口文件中暴露了 `apiRequest` 方法,适用于本项目的二次封装,用于请求数据,可根据实际需求进行配置。
### 构建
项目提供了 Docker 构建配置文件 `Dockerfile` 和 Jenkins 构建配置文件 `jenkinsfile`,根据实际需求进行修改配置。
## 核心包 `@peace/react_client`
核心包除提供封装的核心内容外,还暴露了一些常用功能:
### `request`
基于 `superagent` 封装的请求方法,使用方式上更接近直觉;
class 构造,使用前需实例化
- 实例化
```javascript
import { message } from 'antd'
import { request } from "@peace/react_client";
const apiRequest = new request({
proxy: '/_api', // 代理前缀 与 `config.cjs` 中的 `proxy` 保持一致 才可生效
userKey: 'user', // session 中的用户键值,用于拼接 token,默认为 `user`,session中没有也不影响使用
message: message, // 全局提示组件,用于提示请求结果(如果需要)
interceptor: (res, err) => { // 拦截器,用于处理请求结果,两参数互斥出现
if (err) {
if (err?.status === 401) {
window.location.replace('/signin');
sessionStorage.clear()
}
return err
}
return res
}
})
```
- 使用
```javascript
apiRequest[method](route,{
body: {}, // 请求体
query: {}, // 请求参数
params: {}, // 请求路径参数
header: {}, // 请求头
timeout: 3000, // 超时时间
tipSuccess:'', // 成功提示
tipFail:'', // 失败提示
tip:'', // 提示(成功 & 失败)
}).then(res => {
const { success, data } = res; // 请求结果
})
```
### Redux 相关
#### `basicAction`
构造 action 的主要工具,可直接使用,无需编写 reducer;可参考目录 'Redux `actions`';
#### `basicReducer`
聚合项目中所有的 action,统一生成匹配 reducer [redux 切片]的工具;
#### `createSlice`
创建一个 redux 切片(reducer);
导出自 `@reduxjs/toolkit`,Redux 官方包;
#### `createStore`
创建一个 redux store;
导出自 `@reduxjs/toolkit`,Redux 官方包;
## 目录结构
```
├── .vscode // vscode 相关配置
| ├── launch.json // 启动命令配置,包含环境变量
| └── settings.json
├── client
│ ├── assets // 静态资源文件夹
│ ├── entry // 服务渲染入口
│ ├── src // 源码
│ │ ├── components // 公共组件
│ │ | ├── errorBoundary.jsx // [预置]错误拦截组件
│ │ | ├── index.js // 入口文件
│ │ | └── upload.jsx // [预置]上传组件
│ │ ├── layout // 布局
│ │ | ├── components // 布局组件
│ │ | ├── container // 容器
│ │ | ├── middleWare //
│ │ | └── index.jsx // 入口文件
│ │ ├── sections // [!]功能模块
│ │ | └── auth // 认证模块
│ │ | ├── actions // Redux actions
│ │ | ├── components // 组件
│ │ | ├── container // 容器
│ │ | ├── index.js // 模块入口文件
│ │ | └── router.js // [!]路由文件
│ │ ├── utils // 工具集
│ │ | ├── api.js // api 路由 map
│ │ | ├── index.js // 入口文件
│ │ | └── parseProcessData.js // [预置]项企表单数据解析
│ │ ├── app.js // 次级入口
│ │ └── app.less // 全局样式
│ └── index.js // 项目入口
├── server // ssr 服务端
│ ├── controllers // 控制器
│ ├── index.js // 入口文件
│ └── routes.js // 路由文件
├── .editorconfig // 代码风格配置
├── .gitignore // git 忽略配置
├── .npmrc // npm 配置
├── config.cjs // 项目配置
├── Dockerfile // Docker 构建配置
├── index.html // 模板文件
├── jenkinsfile // Jenkins 构建配置
├── package.json
├── README.md // 项目说明
```