类别 | 选择 |
---|---|
框架 | react |
JS语言 | TypeScript |
CSS语言 | css-modules+less+postcss |
JS编译 | babel |
模块打包 | webpack全家桶 |
单元测试 | jest+enzyme+puppteer+jsdom |
路由 | react-router |
数据流 | dva+redux生态 |
代码风格 | eslint+prettier |
JS压缩 | TerserJS |
CSS压缩 | cssnano |
请求库 | umi-request |
UI | AntDesign+AntDesignPro |
国际化 | react-intl |
hooks库 | umi-hooks |
静态文档 | docz |
微前端 | qiankun |
图表库 | antv |
Ant Design Pro
是一个企业级中后台前端/设计解决方案,我们秉承 Ant Design 的设计价值观,致力于在设计规范和基础组件的基础上,继续向上构建,提炼出典型模板/业务组件/配套设计资源,进一步提升企业级中后台产品设计研发过程中的『用户』和『设计者』的体验。npm config set python "C:/Python38/python.exe"
yarn create umi
├── config # umi 配置,包含路由,构建等配置
├── mock # 本地模拟数据
├── public
│ └── favicon.png # Favicon
├── src
│ ├── assets # 本地静态资源
│ ├── components # 业务通用组件
│ ├── e2e # 集成测试用例
│ ├── layouts # 通用布局
│ ├── models # 全局 dva model
│ ├── pages # 业务页面入口和常用模板
│ ├── services # 后台接口服务
│ ├── utils # 工具库
│ ├── locales # 国际化资源
│ ├── global.less # 全局样式
│ └── global.ts # 全局 JS
├── tests # 测试工具
├── README.md
└── package.json
安装依赖
git init
npm install
启动项目
npm start
config.ts
export default {
plugins,
+ block: {
+ defaultGitUrl: 'https://github.com/ant-design/pro-blocks',
+ },
umi block list
UserRegister (https://preview.pro.ant.design/https://preview.pro.ant.design/user/register)
UserRegisterResult (https://preview.pro.ant.design/https://preview.pro.ant.design/user/register/result)
请输入输出安装区块的路径 /user/register-result
src\pages\user\register\index.tsx
onGetCaptcha = () => {
+ const { dispatch, form } = this.props;
+ const mobile = form.getFieldValue('mobile');
+ dispatch({
+ type: 'login/getCaptcha',
+ payload: mobile,
+ })
let count = 59;
this.setState({ count });
this.interval = window.setInterval(() => {
count -= 1;
this.setState({ count });
if (count === 0) {
clearInterval(this.interval);
}
}, 1000);
};
+ <FormItem>
+ {getFieldDecorator('currentAuthority', {
+ rules: [
+ {
+ required: true,
+ message: formatMessage({ id: 'userandregister.currentAuthority.required' }),
+ }
+ ],
+ })(
+ <Select placeholder={formatMessage({ id: 'userandregister.currentAuthority.placeholder' })}>
+ <Option value="user">普通用户</Option>
+ <Option value="admin">管理员</Option>
+ </Select>
+ )}
+ </FormItem>
src\pages\user\register\locales\zh-CN.ts
+ 'userandregister.currentAuthority.placeholder': '角色',
+ 'userandregister.currentAuthority.required': '请输入邮箱地址!',
src\pages\user\register\service.ts
import request from '@/utils/request';
import { UserRegisterParams } from './index';
export async function fakeRegister(params: UserRegisterParams) {
+ return request('/server/api/register', {
method: 'POST',
data: params,
});
}
src\services\login.ts
export async function getFakeCaptcha(mobile: string) {
+ return request(`/server/api/login/captcha?mobile=${mobile}`);
}
src\services\login.ts
export async function fakeAccountLogin(params: LoginParamsType) {
+ return request('/server/api/login/account', {
method: 'POST',
data: params,
});
}
src\services\user.ts
export async function queryCurrent(): Promise<any> {
+ return request('/server/api/currentUser');
}
src\models\login.ts
if (response.status === 'ok') {
+ if (response.token) {
+ localStorage.setItem('token', response.token);
+ }
const urlParams = new URL(window.location.href);
src\utils\request.ts
const request = extend({
errorHandler, // 默认错误处理
credentials: 'include', // 默认请求是否带上cookie
});
+const baseURL = 'http://localhost:4000';
+request.interceptors.request.use((url: any, options: any) => {
+ if (localStorage.getItem('token')) {
+ options.headers.Authorization = 'Bearer ' + localStorage.getItem('token')
+ }
+ if (url.startsWith('/server')) {
+ url = baseURL + url.slice(7);
+ }
+ return { url, options };
+});
export default request;
FROM nginx
LABEL name="antdesign-front"
LABEL version="1.0"
COPY ./dist/ /usr/share/nginx/html/
COPY ./antdesign-front.conf /etc/nginx/conf.d/
EXPOSE 80
.git
node_modules
package-lock.json
Dockerfile
.dockerignore
antdesign-front.conf
server {
listen 80;
server_name 47.104.204.74;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
}
let express = require("express");
let bodyParser = require("body-parser");
let jwt = require('jwt-simple');
let cors = require("cors");
let Models = require('./db');
let sendCode = require('./sms');
let session = require("express-session");
let MongoStore = require('connect-mongo')(session);
let config = process.env.NODE_ENV == 'production' ? require('./config/config.prod') : require('./config/config.dev');
let app = express();
app.use(
cors({
origin: config.origin,
credentials: true,
allowedHeaders: "Content-Type,Authorization",
methods: "GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS"
})
);
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(
session({
secret: config.secret,
resave: false,
saveUninitialized: true,
store: new MongoStore({
url: config.dbUrl,
mongoOptions: {
useNewUrlParser: true,
useUnifiedTopology: true
}
})
})
);
app.get('/', async (req, res) => {
res.json({ code: 0, data: `hello` });
});
app.get('/api/login/captcha', async (req, res) => {
let mobile = req.query.mobile;
let captcha = rand();
req.session.captcha = captcha;
await sendCode(mobile, captcha);
res.json({ code: 0, data: `[仅限测试环境验证码]: ${captcha}` });
});
app.post('/api/register', async (req, res) => {
let user = req.body;
if (user.captcha != req.session.captcha) {
return res.json({ code: 1, error: '验证码不正确' });
}
let avatarValue = require('crypto').createHash('md5').update(user.mail).digest('hex');
user.avatar = `https://secure.gravatar.com/avatar/${avatarValue}?s=48`;
user = await Models.UserModel.create(user);
res.send({ status: 'ok', currentAuthority: 'user' });
});
app.post('/api/login/account', async (req, res) => {
let user = req.body;
let query = {};
if (user.type == 'account') {
query.mail = user.userName;
} else if (user.type == 'mobile') {
query.mobile = user.mobile;
if (user.captcha != req.session.captcha) {
return res.send({
status: 'error',
type: user.type,
currentAuthority: 'guest',
});
}
}
let dbUser = await Models.UserModel.findOne(query);
if (dbUser) {
dbUser.userid = dbUser._id;
dbUser.name = dbUser.mail;
let token = jwt.encode(dbUser, config.secret);
res.send({ status: 'ok', token, type: user.type, currentAuthority: dbUser.currentAuthority });
} else {
return res.send({
status: 'error',
type: user.type,
currentAuthority: 'guest',
});
}
});
app.get('/api/currentUser', async (req, res) => {
let authorization = req.headers['authorization'];
if (authorization) {
try {
let user = jwt.decode(authorization.split(' ')[1], config.secret);
user.userid = user._id;
user.name = user.mail;
res.json(user);
} catch (err) {
res.status(401).send({});
}
} else {
res.status(401).send({});
}
});
app.listen(4000, () => {
console.log('服务器在4000端口启动!');
});
function rand() {
let min = 1000, max = 9999;
return Math.floor(Math.random() * (max - min)) + min;
}
db.js
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const ObjectId = Schema.Types.ObjectId;
let configs = process.env.NODE_ENV == 'production' ? require('./config/config.prod') : require('./config/config.dev');
const conn = mongoose.createConnection(configs.dbUrl, { useNewUrlParser: true, useUnifiedTopology: true });
const UserModel = conn.model('User', new Schema({
userid: { type: String },//邮箱
name: { type: String },
mail: { type: String, required: true },//邮箱
password: { type: String, required: true },//密码
mobile: { type: String, required: true },//手机号
avatar: { type: String, required: true },//头像
currentAuthority: { type: String, required: true }//当前用户的权限
}));
module.exports = {
UserModel
}
config\config.prod.js
module.exports = {
secret: 'zhufengcms',
dbUrl: "mongodb://antdesign-mongo:27017/zhufengcms",
origin: ["http://47.104.204.74", "http://47.104.204.74:8000"]
}
config\config.dev.js
module.exports = {
secret: 'zhufengcms',
dbUrl: "mongodb://localhost:27017/zhufengcms",
origin: ["http://localhost:8000"]
}
sms.js
const axios = require('axios');
const smsConfig = require('./smsConfig');
//http://docs.ucpaas.com/doku.php?id=%E7%9F%AD%E4%BF%A1:sendsms
module.exports = async (mobile, captcha) => {
const url = 'https://open.ucpaas.com/ol/sms/sendsms';
let result = await axios({
method: 'POST',
url,
data: {
sid: smsConfig.sid,
token: smsConfig.token,
appid: smsConfig.appid,
templateid: smsConfig.templateid,
param: captcha,
mobile
},
headers: {
"Content-Type": "application/json;charset=utf-8",
"Accept": "application/json"
}
})
return result;
}
smsConfig.js
module.exports = {
sid: '32548fb951ac0df279db0e6e9a515566', //开发者账号id
token: 'aa0309c08920ca38201de69eb3c745b6', //开发者token
appid: '16129d504b7c484c9e8f09b4ec929983', //应用id
templateid: '387675' //短信模板id
}
package.json
"scripts": {
"start": "node api.js"
},
Dockerfile
FROM node
ENV NODE_ENV production
LABEL name="antdesign-server"
LABEL version="1.0"
COPY . /app
WORKDIR /app
RUN npm install
EXPOSE 4000
CMD npm start
.dockerignore
.git
node_modules
package-lock.json
Dockerfile
.dockerignore
#升级所有包同时也升级软件和系统内核
yum update -y
#只升级所有包,不升级软件和系统内核
yum upgrade
Docker
属于 Linux 容器的一种封装,提供简单易用的容器使用接口。Docker
将应用程序与该程序的依赖,打包在一个文件里面。运行这个文件,就会生成一个虚拟容器。程序在这个虚拟容器里运行,就好像在真实的物理机上运行一样yum install -y yum-utils device-mapper-persistent-data lvm2
yum-config-manager \
--add-repo \
https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
yum install -y docker-ce docker-ce-cli containerd.io
mkdir -p /etc/docker
tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://fwvjnv59.mirror.aliyuncs.com"]
}
EOF
# 重载所有修改过的配置文件
systemctl daemon-reload
systemctl restart docker
yum install git -y
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.1/install.sh | bash
source /root/.bashrc
nvm ls-remote
nvm install v12.13.1
npm i cnpm -g
docker network create --driver bridge antdesign
docker network connect antdesign antdesign-mongo
docker network inspect antdesign
docker pull mongo:latest
docker images
docker run -d --name antdesign-mongo -p 27017:27017 --net antdesign mongo
docker ps
docker exec -it antdesign-mongo bash
mongo
vim /etc/yum.repos.d/mongodb-org-4.0.repo
#添加以下内容:
[mongodb-org-4.0]
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/4.0/x86_64/
gpgcheck=0
enabled=1
gpgkey=https://www.mongodb.org/static/pgp/server-4.0.asc
#这里可以修改 gpgcheck=0, 省去gpg验证
[root@localhost ~]# yum makecache
yum -y install mongodb-org
whereis mongod
vim /etc/mongod.conf
systemctl start mongod.service #启动
systemctl stop mongod.service #停止
systemctl status mongod.service #查看状态
systemctl stop firewalld.service #停止firewall
systemctl disable firewalld.service #禁止firewall开机启动
git clone https://gitee.com/zhufengpeixun/antdesign-server.git
cd antdesign-server
docker build -t antdesign-server .
docker image ls
docker run -d --name antdesign-server -p 4000:4000 --net antdesign antdesign-server
curl http://localhost:4000
git clone https://gitee.com/zhufengpeixun/antdesign-front.git
cd antdesign-front
cnpm install
cnpm run build
docker build -t antdesign-front .
docker run -d --name antdesign-front -p 80:80 --net antdesign antdesign-front