技术栈选型

react、ant design pro(一款基于 ant design 和 umi 封装的一套企业级中后台前端/设计解决方案,开箱即用),封装的很厉害,学习成本较高,推荐有 react 全家桶基础的同学使用。使用前请阅读 新手需知

补充了解或解决常见 bug :https://www.yuque.com/moyan-awh3b/nccb2c/ccykge?

初始化项目

我们提供了 pro-cli 来快速的初始化脚手架。

1
2
3
# 使用 npm
npm i @ant-design/pro-cli -g # 安装全局 cli 命令,只用一次以后就不用安装了
pro create myapp # myapp 是项目名称

选择 umi 的版本(我们选择 umi3)

1
2
3
? 🐂 使用 umi@4 还是 umi@3 ? (Use arrow keys)
umi@4
❯ umi@3
1
2
3
? 🚀 要全量的还是一个简单的脚手架? (Use arrow keys)
❯ simple
complete

安装依赖:

1
2
3
$ cd myapp
// 或
$ cd myapp && npm install

将项目跑起来

1
$ npm run start # 此命令会开启 mock,具体看 package.json

项目文件介绍

文件夹/文件 介绍
.vscode 图片.png vscode 配置
config 图片.png 项目全局配置(路由,代理等文件存放处)
dist 图片.png build 生成目录,供部署上线使用
mock 图片.png 模拟数据接口存放处
public 图片.png 存放一些静态资源,比如这个网站的 logo 图标、视频音频等等
src 图片.png 组件和页面存放处
components 图片.png 组件存放
e2e 图片.png 集成测试
pages 图片.png 存放页面
.umi 运行时配置
locales 图片.png 国际化组件
图片.png 接口文档工具
services - ant-design-pro 定义了项目后端接口
图片.png 定义了项目后端接口(官方)
图片.png 项目的入口,整个前端项目的启动离不开这个文件
图片.png 全局样式的代码(使用的是 less 预处理器)
图片.png 全局的脚本文件
图片.png 前端页面缓存
图片.png 定义了一些 ts 的类型 (类似于 c、c++的宏定义)
图片.png 测试
图片.png 编辑器的配置 (定义项目编写习惯,编辑器会根据定义规则帮你格式化代码)
图片.png 美化前端代码的工具
图片.png 检查 js 语法
图片.png 测试工具
图片.png 检验 css 语法
图片.png 自动化测试工具,帮你在火狐或谷歌自动测试,不用真实地打开浏览器就能测试

项目瘦身

  1. 移除国际化(原理:使用 umi 的 @umijs/plugin-locale 暴露的 setLocale 实现,具体看 https://pro.ant.design/zh-CN/docs/i18n)、删除国际化对应的 locales 文件夹
1
npm run i18n-remove # 执行完后使用 i18n 的地方会被全中文替代,如需用英文可以在 package.json 修改此命令
  1. 删除 oneapi.json 文件和 config.js 中的 openApi 配置 (移除 mock 数据)
  2. 删除 e2e、swagger、tests、jest.config.js

img

部署

方式:宝塔 + github action,前提是你需要有一个云服务器。

宝塔安装

Linux 运维面板

官方安装教程:https://www.bt.cn/new/download.html

方便管理服务器、方便安装软件

创建站点
image-20221007181103134

github action 自动部署到云服务器

项目根目录下创建 .github/workflows/push.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# 一个workflow,名为deploy to tengxunyun
name: deploy to tengxunyun

on: # 此CI/CD触发时的事件
push: # 在代码提交时自动触发
branches:
- master

# 一个 CI/CD 的工作流有许多 jobs 组成,比如最典型的 job 是 lint,test,build。
jobs:
build: # 构建job
runs-on: ubuntu-latest # 跑workflow的服务器系统
steps: # job的一系列动作
# 切换分支获取源码
- name: Checkout # step的名称,将会在 github action 的控制台中显示
# 选择一个action,可以理解为若干 steps.run,有利于代码复用
uses: actions/checkout@master
# 安装使用 node:10
- name: use Node.js 10
uses: actions/setup-node@v1
with:
node-version: 16
# 运行命令,npm install && npm run build
- name: yarn install and build
run: |
yarn install
yarn build
env:
CI: true

- name: 部署到云服务器
uses: cross-the-world/scp-pipeline@v1.2.1
with:
host: ${{ secrets.USER_HOST }} #云服务器ip地址:如 14.215.177.39
user: ${{ secrets.USER_NAME }}
pass: ${{ secrets.USER_PASS }}
connect_timeout: 30s
local: './dist/*'
remote: /www/wwwroot/dot.hellozero.site/sjx-admin

关于部署到云服务器配置(cross-the-world/scp-pipeline@v1.2.1

secrets.USER_HOST、secrets.USER_NAME、secrets.USER_PASS 需要在 github 远程仓库 settings 中设置

  • USER_HOST:云服务器 ip 地址(如 14.215.177.39)
  • USER_NAME:云服务器用户名 (腾讯云阿里云一般为 root)
  • USER_PASS:云服务器密码

image-20221007174959981

local 指的是项目打包后 output 的路径名,一般为 dist 不用修改

remote 静态文件推送到服务器中的位置,在宝塔中需要先生成一个静态站点。

刷新后 nginx 404 的问题

宝塔设置伪静态解决 部署后刷新 nginx 404 的问题

image-20221007174340404

1
2
3
location /sjx-admin {
try_files $uri /sjx-admin/index.html;
}

踩坑记录

  1. JSON.parse() 它不会转换为空字符串,会产生 Uncaught SyntaxError 。

    1
    2
    JSON.parse(localStorage.getItem('userInfo') || ''); // 错误的
    JSON.parse(localStorage.getItem('userInfo') || '0'); // 正确的
  2. img 标签访问图片时返回 403 forbidden 的问题 ?需要在页面头部设置 <meta name="referrer" content="no-referrer" />

  3. 如何在 ant design pro 中添加 mata 标签 ?由于 ant design pro 配置被 umi 的 defineConfig 托管了,所以在 umi 的 config 文件中配置即可。具体位置 config/config.ts 默认暴露的 defineConfig({}) 中设置类似 metas: [{ name: ‘referrer’, content: ‘never’ }] 。

登录页

界面

首先注意组件 LoginForm 是由 pro-components 基于 ant design 封装好的高级组件。具体的 API 可以查看官网。

魔改 ant-design-pro 生成的登录页成自己想要的?要改变细节一般通过传入 props 参数和组件 <LoginForm>...填写内容</LoginForm> ,可以理解为 vue 中的插槽的内容。

登录逻辑

分以下四步实现…

前端审核校验

用户正常输入账号密码

账号密码的规则校验

点击登录按钮后调用 LoginForm 组件的 onFinish props 传入的回调函数

验证账号密码是否合规

对接后端 api

合规后根据 API 发送网络请求给后端,或者用前端 mock 模拟登录。(由于项目使用了 TS, 一些返回值和传入值得写类型限定,没有学 TS 的同学可以直接 any 一把刷)

保存登录态与用户信息

通过登录返回登录态去获取用户的信息,本项目中是 currentUser。

储存用户信息和刷新用户信息的方法统一交给 umi dvaplugin-initial-state 插件管理。封装了 react-redux,用起来特别方便,和 vuex 差不多。登录态也在 localstorage 中储存一份。

后续你就能看懂了!

umi 侧边栏菜单 icon 修改(引入本地图片)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// MenuIcon.tsx
import IconAlgorithm from '@/assets/icons/menu/algorithm.png'; // 引入本地的 icon 图标

export const IconMap = {
algorithm: IconAlgorithm,
};

export const MenuIcon = (imgSrc: any) => {
return (
<span className="anticon">
<img
style={{
width: 16,
height: 16,
position: 'relative',
left: 0,
top: -4,
overflow: 'hidden',
margin: -2,
}}
src={imgSrc}
alt="icon"
/>
</span>
);
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Layout.tsx
const PNG = '|png';

const menuDataRender = (menuList: MenuDataItem[]): MenuDataItem[] => {
return menuList.map(item => {
return {
...item,
children: item.children ? menuDataRender(item.children) : undefined,
icon:
typeof item.icon === 'string' && item.icon.indexOf(PNG) > -1
? MenuIcon(IconMap[item.icon.replace(PNG, '')])
: item.icon,
};
});
};
1
2
3
4
5
6
7
// routes.ts 添加一个自定义 icon 的路由
{
name: 'xxx',
icon: 'xxx|png',
path: '/xxx',
component: './xxx/index'
},

图片上传

文件在上传前需要给文件重命名

坑:文件名字是只读的,无法重写。

解决:基于源文件 new File([源文件], 新文件名 , { type: 文件类型 }) 出来,名字修改成新的即可。

手动上传文件

使用 antd Upload 组件完成。将文件提交到后端时,一般需要在 headers 中设置 { "Content-Type": "multipart/form-data" }

文件本地预览

  1. 使用钩子 antd Upload beforeUpload
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const getBase64 = (file: RcFile): Promise<string> =>
new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result as string);
reader.onerror = error => reject(error);
});

const beforeUpload = async file => {
const res = await getBase64(file); // 将文件转化为 base64 地址
file.thumbUrl = res; // 将 base64 地址赋值到 thumbUrl(缩略图属性)中
// ...

return false; // 设置为手动提交
};
  1. 记得将 Upload 设置文件展示方式为 listType="picture-card" | "picture" , 才能展示出缩略图