You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
279 lines
9.9 KiB
279 lines
9.9 KiB
2 years ago
|
创建时间:2022/1/28
|
||
|
|
||
|
最后修改时间: 2022/1/28
|
||
|
|
||
|
## 1. 项目说明:
|
||
|
|
||
|
- 项目名称: 南昌市政隧道综合管理平台
|
||
|
- 开发技术栈: node12+, React17+, antd4.X.
|
||
|
- 代码 svn 路径: http://10.8.30.22/FS-Anxinyun/truck/codes/web/console
|
||
|
- 开发人员: 徐蒙、彭鹏、孔斌
|
||
|
- 备注信息:
|
||
|
|
||
|
## 2. 文档维护:
|
||
|
|
||
|
- 文档相关内容若有更改,请及时更新文档,以备后来者查询;
|
||
|
|
||
|
## 3. 项目开发:
|
||
|
|
||
|
- 请遵循此文档约定的目录结构与约定
|
||
|
|
||
|
```js
|
||
|
|-- .babelrc
|
||
|
|-- color.js
|
||
|
|-- config.js
|
||
|
|-- Dockerfile
|
||
|
|-- jsconfig.json
|
||
|
|-- package.json
|
||
|
|-- readme.md
|
||
|
|-- server.js
|
||
|
|-- webpack.config.js
|
||
|
|-- webpack.config.prod.js
|
||
|
|-- .vscode
|
||
|
| |-- launch.json
|
||
|
| |-- settings.json
|
||
|
|-- client
|
||
|
| |-- index.ejs
|
||
|
| |-- index.html // 当前 html 文件
|
||
|
| |-- index.js
|
||
|
| |-- assets // 资源文件
|
||
|
| | |-- color.less
|
||
|
| | |-- files
|
||
|
| | |-- fonticon
|
||
|
| | |-- font_sc
|
||
|
| | |-- images
|
||
|
| | |-- avatar
|
||
|
| | |-- loginUi
|
||
|
| |-- src // 项目代码
|
||
|
| |-- app.js // 由此开始并加载模块
|
||
|
| |-- index.js
|
||
|
| |-- components // 公用组件
|
||
|
| | |-- index.js // 由此导出组件
|
||
|
| | |-- Upload
|
||
|
| | |-- index.js
|
||
|
| |-- layout // 项目布局以及初始化等操作
|
||
|
| | |-- index.js
|
||
|
| | |-- actions
|
||
|
| | | |-- global.js
|
||
|
| | |-- components
|
||
|
| | | |-- footer
|
||
|
| | | | |-- index.js
|
||
|
| | | | |-- style.css
|
||
|
| | | |-- header
|
||
|
| | | | |-- index.js
|
||
|
| | | | |-- style.css
|
||
|
| | | |-- sider
|
||
|
| | | |-- index.js
|
||
|
| | |-- containers
|
||
|
| | | |-- index.js
|
||
|
| | | |-- layout
|
||
|
| | | | |-- breadcrumb.js // 面包屑组件
|
||
|
| | | | |-- index.js
|
||
|
| | | | |-- index.less
|
||
|
| | | |-- no-match
|
||
|
| | | |-- index.js
|
||
|
| | |-- reducers
|
||
|
| | | |-- ajaxResponse.js
|
||
|
| | | |-- global.js // 全局数据,主要包含屏幕可视宽高、所有的 action 等
|
||
|
| | | |-- index.js
|
||
|
| | |-- store
|
||
|
| | |-- index.js
|
||
|
| | |-- store.dev.js
|
||
|
| | |-- store.prod.js
|
||
|
| |-- sections // 各功能模块
|
||
|
| | |-- auth // 比较特别的 Auth 模块,目前 action、reducer 依然采用原始写法;包含登录、忘记密码等项目基本功能页面
|
||
|
| | | |-- index.js
|
||
|
| | | |-- routes.js
|
||
|
| | | |-- actions
|
||
|
| | | | |-- auth.js
|
||
|
| | | | |-- index.js
|
||
|
| | | |-- components
|
||
|
| | | |-- containers
|
||
|
| | | | |-- index.js
|
||
|
| | | | |-- login.js
|
||
|
| | | |-- reducers
|
||
|
| | | | |-- auth.js
|
||
|
| | | | |-- index.js
|
||
|
| | | |-- __tests__
|
||
|
| | |-- example // 示例模块,一般的功能模块应遵循此结构
|
||
|
| | |-- index.js // 由此导出该模块信息,应包括一个 key 值,actions 等
|
||
|
| | |-- nav-item.js // 用于生成菜单项,此文件内可以进行权限判断
|
||
|
| | |-- routes.js // 路由文件
|
||
|
| | |-- style.less // 样式文件,若样式并不是非常多,每个模块一个样式文件即可
|
||
|
| | |-- actions
|
||
|
| | | |-- example.js // 具体的 action 操作
|
||
|
| | | |-- index.js // 由此导出该项目的 action
|
||
|
| | |-- components // 组件
|
||
|
| | |-- containers // 容器,此文件夹内应只包括该模块第一层级的页面
|
||
|
| | | |-- example.js
|
||
|
| | | |-- index.js
|
||
|
| | |-- reducers // 若采用封装后的 action 写法,则 reducer 可不写
|
||
|
| | |-- index.js
|
||
|
| |-- styles // 待初始化的主题样式
|
||
|
| | |-- antd.less
|
||
|
| | |-- theme.less
|
||
|
| |-- themes // 初始化后的主题样式文件
|
||
|
| | |-- dark.json
|
||
|
| | |-- light.json
|
||
|
| | |-- theme.json
|
||
|
| |-- utils //
|
||
|
| |-- authCode.js
|
||
|
| |-- func.js // 常用函数
|
||
|
| |-- index.js
|
||
|
| |-- region.js
|
||
|
| |-- webapi.js // api 路由
|
||
|
|-- log
|
||
|
|-- middlewares
|
||
|
| |-- proxy.js
|
||
|
| |-- webpack-dev.js
|
||
|
|-- routes
|
||
|
| |-- index.js
|
||
|
| |-- attachment
|
||
|
|-- typings
|
||
|
|-- node
|
||
|
| |-- node.d.ts
|
||
|
|-- react
|
||
|
|-- react.d.ts
|
||
|
```
|
||
|
|
||
|
- 封装后一般 action 写法:
|
||
|
|
||
|
`@peace/utils 的 actionHelp 中有详细注释`
|
||
|
|
||
|
```js
|
||
|
"use strict";
|
||
|
|
||
|
import { basicAction } from "@peace/utils";
|
||
|
import { ApiTable } from "$utils";
|
||
|
|
||
|
export function getMembers(orgId) {
|
||
|
return (dispatch) =>
|
||
|
basicAction({
|
||
|
type: "get",
|
||
|
dispatch: dispatch,
|
||
|
actionType: "GET_MEMBERS",
|
||
|
url: `${ApiTable.getEnterprisesMembers.replace(
|
||
|
"{enterpriseId}",
|
||
|
orgId
|
||
|
)}`,
|
||
|
msg: { error: "获取用户列表失败" },
|
||
|
reducer: { name: "members" },
|
||
|
});
|
||
|
}
|
||
|
```
|
||
|
|
||
|
1. 若 type=post,则可以使用 data 属性发送对象格式数据;
|
||
|
|
||
|
2. reducer.name 会作为该 action 对应的 reducer 的名字,从 state 里可以解构此变量,获得该 action 异步或其他操作获得的数据;
|
||
|
|
||
|
3. msg 可以发送 `{ option:'获取用户列表' }` ,则 actionHelp 会自动将其处理为失败和成功两种情况;
|
||
|
|
||
|
若单独写 success 或 error 的 key,则只在成功或失败的时候进行提示;
|
||
|
|
||
|
4. 后续可以优化:type=get 时候,
|
||
|
|
||
|
使用 query 属性将数据传递,在 @peace/utils 的 actionHelp 中将其添加到路由后面;eg. `{ enterpriseId: orgId }`
|
||
|
|
||
|
使用 replace 属性传递对象数据,对象数据中将被替换的值为 key,替换的值为 value,然后再 actionHelp 中更改路由;eg. `{ "{enterpriseId}": orgId}`
|
||
|
|
||
|
5. 最终取得的 reducer 中的数据格式一般为:
|
||
|
```js
|
||
|
{
|
||
|
data: xxx, // 接口返回的数据格式
|
||
|
isRequesting: false, // 请求状态
|
||
|
success: true, // 以此判断请求是否成功,不用再以 payload.type 判断
|
||
|
}
|
||
|
```
|
||
|
|
||
|
- actions 的引用
|
||
|
|
||
|
从 reducer 的 state.global.actions 里引用具体 action
|
||
|
|
||
|
```js
|
||
|
const Example = (props) => {
|
||
|
const { dispatch, actions, user, loading } = props;
|
||
|
|
||
|
useEffect(() => {
|
||
|
dispatch(actions.example.getMembers(user.orgId));
|
||
|
}, []);
|
||
|
|
||
|
return (
|
||
|
<Spin tip="biubiubiu~" spinning={loading}>
|
||
|
example
|
||
|
</Spin>
|
||
|
);
|
||
|
};
|
||
|
|
||
|
function mapStateToProps(state) {
|
||
|
const { auth, global, members } = state;
|
||
|
return {
|
||
|
loading: members.isRequesting,
|
||
|
user: auth.user,
|
||
|
actions: global.actions,
|
||
|
members: members.data,
|
||
|
};
|
||
|
}
|
||
|
|
||
|
export default connect(mapStateToProps)(Example);
|
||
|
```
|
||
|
|
||
|
- 一般路由配置
|
||
|
|
||
|
```js
|
||
|
"use strict";
|
||
|
import { Example } from "./containers";
|
||
|
|
||
|
export default [
|
||
|
{
|
||
|
type: "inner", // 是否在layout 内,如果为outer,则看不到 header、footer、sider等布局,比如登陆页面
|
||
|
route: {
|
||
|
path: "/example",
|
||
|
key: "example",
|
||
|
breadcrumb: "栗子",
|
||
|
// 不设置 component 则面包屑禁止跳转
|
||
|
childRoutes: [
|
||
|
{
|
||
|
path: "/e1", // 自路由不必复写父路由内容,会自动拼接; 则此处组件的实际路由为 /example/e1
|
||
|
key: "e1",
|
||
|
component: Example,
|
||
|
breadcrumb: "棒子",
|
||
|
},
|
||
|
],
|
||
|
},
|
||
|
},
|
||
|
];
|
||
|
```
|
||
|
|
||
|
- cross-env 的使用限制
|
||
|
|
||
|
cross-env 可以统一不同操作系统下环境变量的导出方式,不用再在 windows 下写 set;linux 下写 export; 可以统一以 cross-env NODE_ENV=DEV 代替;
|
||
|
|
||
|
但是这样的话就不能在同一条运行的命令中使用 && 切割,因为会把命令切割为两个环境,则最终拿不到我们设置的变量;
|
||
|
|
||
|
- 主题变换
|
||
|
|
||
|
核心实现代码:
|
||
|
|
||
|
```js
|
||
|
// client/src/layout/components/header/index.js
|
||
|
|
||
|
const changeTheme_ = (themeKey) => {
|
||
|
localStorage.setItem("theme-name", themeKey);
|
||
|
window.less.modifyVars(themeMap[themeKey]).catch((error) => {
|
||
|
message.error(`Failed to reset theme`);
|
||
|
});
|
||
|
};
|
||
|
```
|
||
|
|
||
|
使用 less 进行样式变量替换;
|
||
|
|
||
|
所以在 client/src/themes/xx.json 中的中可以配置想变换的主题变量,变量的获取可以通过查看 antd、antdPro 的源码,然后在 color 中处理;
|
||
|
|
||
|
## 一些考量
|
||
|
|
||
|
1. 安心云 4.0 的登录页定制:因为登录页本身并不复杂,所以可以把众多登录页分类,比如简单的替换背景、背景+登录框、更多动态效果等,每一类有一个登录文件,登录文件中将样式抽取出来作为配置项导入使用。可以避免多样式多要求造成的混乱;
|
||
|
|
||
|
2. 安心云 4.0 即作为业主侧,也要作为本地化部署,则为了两种模式兼容,可以在本地化部署的数据库默认生成一个项目以及约定的 pcode,写在登录的代码里,看起来登录的是一个整体的系统,实际登录的是一个默认生成的项目,可以消除数据切割的工作;
|
||
|
|
||
|
3. 文件上传,如需保存在 api 所在服务器,可以在 api 使用 @fs/attachment 包配合 client/src/component/Upload 使用,Upload 组件已经完美兼容该包的使用;
|