mirror of https://github.com/sunface/rust-course
parent
2ac6012912
commit
36354ab653
@ -0,0 +1,4 @@
|
|||||||
|
ENV = 'development'
|
||||||
|
|
||||||
|
# base api
|
||||||
|
REACT_APP_ADMIN_BASE_API = '/dev-api'
|
@ -0,0 +1,4 @@
|
|||||||
|
ENV = 'production'
|
||||||
|
|
||||||
|
# base api
|
||||||
|
REACT_APP_ADMIN_BASE_API = '/pro-api'
|
@ -0,0 +1,60 @@
|
|||||||
|
const {
|
||||||
|
override,
|
||||||
|
addDecoratorsLegacy,
|
||||||
|
fixBabelImports,
|
||||||
|
addLessLoader,
|
||||||
|
addWebpackAlias
|
||||||
|
// addWebpackPlugin
|
||||||
|
} = require('customize-cra')
|
||||||
|
const themeVariables = require('./src/styles/theme/themeVariables')
|
||||||
|
const AntDesignThemePlugin = require('antd-theme-webpack-plugin')
|
||||||
|
const path = require('path')
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
antDir: path.join(__dirname, './node_modules/antd'), // antd包位置
|
||||||
|
stylesDir: path.join(__dirname, './src/styles'), //主题文件所在文件夹
|
||||||
|
varFile: path.join(__dirname, './src/styles/vars.less'), // 自定义默认的主题色
|
||||||
|
mainLessFile: path.join(__dirname, './src/styles/main.less'), // 项目中其他自定义的样式(如果不需要动态修改其他样式,该文件可以为空)
|
||||||
|
outputFilePath: path.join(__dirname, './public/color.less'), //提取的less文件输出到什么地方
|
||||||
|
themeVariables: themeVariables, //要改变的主题变量
|
||||||
|
indexFileName: './public/index.html', // index.html所在位置
|
||||||
|
generateOnce: false // 是否只生成一次
|
||||||
|
}
|
||||||
|
const addTheme = () => (config) => {
|
||||||
|
config.plugins.push(new AntDesignThemePlugin(options))
|
||||||
|
return config
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = override(
|
||||||
|
// 使用 Day.js 替换 momentjs 优化打包大小
|
||||||
|
// addWebpackPlugin(
|
||||||
|
|
||||||
|
// ),
|
||||||
|
// 装饰器语法
|
||||||
|
addDecoratorsLegacy(),
|
||||||
|
// 自动加载antd
|
||||||
|
fixBabelImports('import', {
|
||||||
|
libraryName: 'antd',
|
||||||
|
libraryDirectory: 'es',
|
||||||
|
style: true
|
||||||
|
}),
|
||||||
|
// less
|
||||||
|
addLessLoader({
|
||||||
|
javascriptEnabled: true,
|
||||||
|
localIdentName: '[local]--[hash:base64:5]'
|
||||||
|
}),
|
||||||
|
// 路径别名
|
||||||
|
addWebpackAlias({
|
||||||
|
'@': path.resolve(__dirname, 'src'),
|
||||||
|
'@library': path.resolve(__dirname, 'src/library'),
|
||||||
|
'@layouts': path.resolve(__dirname, 'src/layouts'),
|
||||||
|
'@utils': path.resolve(__dirname, 'src/library/utils'),
|
||||||
|
'@pages': path.resolve(__dirname, 'src/pages'),
|
||||||
|
'@store': path.resolve(__dirname, 'src/store'),
|
||||||
|
'@styles': path.resolve(__dirname, 'src/styles'),
|
||||||
|
'@components': path.resolve(__dirname, 'src/components'),
|
||||||
|
'@http': path.resolve(__dirname, 'src/library/utils/http')
|
||||||
|
}),
|
||||||
|
// 主题
|
||||||
|
addTheme()
|
||||||
|
)
|
@ -0,0 +1,31 @@
|
|||||||
|
[react 文档](https://zh-hans.reactjs.org/)
|
||||||
|
|
||||||
|
[Eslint 参考资料](https://blog.csdn.net/walid1992/article/details/54633760)
|
||||||
|
|
||||||
|
[mock 文档](http://mockjs.com/)
|
||||||
|
|
||||||
|
[json-server 参考资料](https://blog.csdn.net/div_ma/article/details/80579971)
|
||||||
|
|
||||||
|
[mockjs 参考资料](https://blog.csdn.net/div_ma/article/details/80592996)
|
||||||
|
|
||||||
|
[mock json-server 虚拟数据服务搭建](https://blog.csdn.net/qq_41629150/article/details/99645632)
|
||||||
|
|
||||||
|
## 安装依赖
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
|
||||||
|
npm install json-server -g
|
||||||
|
|
||||||
|
yarn global add json-server
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## 使用 concurrently 并行地运行多个命令
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
|
||||||
|
npm i concurrently --save
|
||||||
|
|
||||||
|
yarn add concurrently
|
||||||
|
|
||||||
|
```
|
@ -0,0 +1,6 @@
|
|||||||
|
module.exports = {
|
||||||
|
HOST: 'localhost', // 定义ip地址
|
||||||
|
PORT: '3023', // 定义端口号
|
||||||
|
DB_FILE: './db.js', // 定义批量模拟数据文件
|
||||||
|
API: '/api'//创建根api名 这里的 /mock 如同 后端真实/api
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
let Mock = require('mockjs')
|
||||||
|
let Random = Mock.Random
|
||||||
|
module.exports = function() {
|
||||||
|
let data = {
|
||||||
|
news: []
|
||||||
|
}
|
||||||
|
|
||||||
|
let images = [1, 2, 3].map( x =>Random.image('200x100', Random.color(), Random.word(2, 6)))
|
||||||
|
|
||||||
|
for (let i = 0; i < 100; i++) {
|
||||||
|
|
||||||
|
let content = Random.cparagraph(0, 10)
|
||||||
|
|
||||||
|
data.news.push({
|
||||||
|
id: i,
|
||||||
|
title: Random.cword(8, 20),
|
||||||
|
desc: content.substr(0, 40),
|
||||||
|
tag: Random.cword(2, 6),
|
||||||
|
views: Random.integer(100, 5000),
|
||||||
|
images: images.slice(0, Random.integer(1, 3))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return data
|
||||||
|
}
|
After Width: | Height: | Size: 318 B |
@ -0,0 +1,114 @@
|
|||||||
|
body {
|
||||||
|
display: flex;
|
||||||
|
min-height: 100vh;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
|
||||||
|
Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
color: #3b4252;
|
||||||
|
letter-spacing: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
max-width: 960px;
|
||||||
|
margin: auto;
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
header a {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
header a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav ul {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav li.title {
|
||||||
|
flex-grow: 5;
|
||||||
|
text-align: left;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 1.4rem;
|
||||||
|
color: #3b4252;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav li {
|
||||||
|
flex-grow: 1;
|
||||||
|
align-self: center;
|
||||||
|
text-align: right;
|
||||||
|
color: #4c566a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-heart {
|
||||||
|
color: deeppink;
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
margin-top: 4rem;
|
||||||
|
border-top: 1px solid #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
margin-top: 4rem;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
i {
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #5e81ac;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
color: #81a1c1;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
td {
|
||||||
|
border: 0;
|
||||||
|
padding: 0 1em 0.5em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
td:first-child {
|
||||||
|
width: 1%;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
list-style-position: inside;
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
list-style-type: none;
|
||||||
|
margin-bottom: 0.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
padding: 0.2rem;
|
||||||
|
margin: 0rem 0.2rem;
|
||||||
|
border-radius: 0.2rem;
|
||||||
|
background: #e5e9f0;
|
||||||
|
}
|
||||||
|
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,4 @@
|
|||||||
|
const API = '/api'
|
||||||
|
module.exports = {
|
||||||
|
[`${API}` + '/*'] : '/$1' // 路由请求由/mock/*接管
|
||||||
|
}
|
@ -1,72 +1,71 @@
|
|||||||
{
|
{
|
||||||
"name": "mafanr",
|
"name": "imdev-ui",
|
||||||
"version": "1.0.0",
|
"version": "0.1.0",
|
||||||
"description": "A Vue.js project",
|
|
||||||
"author": "sunface <cto@188.com>",
|
|
||||||
"private": true,
|
"private": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@ant-design/dark-theme": "^0.2.2",
|
||||||
|
"@antv/data-set": "^0.10.2",
|
||||||
|
"@antv/g2plot": "^0.11.5",
|
||||||
|
"@types/jest": "^24.0.25",
|
||||||
|
"@types/node": "^13.1.6",
|
||||||
|
"@types/react": "^16.9.17",
|
||||||
|
"@types/react-dom": "^16.9.4",
|
||||||
|
"@types/react-responsive": "^8.0.2",
|
||||||
|
"@types/react-router-dom": "^5.1.2",
|
||||||
|
"antd": "3.26.6",
|
||||||
|
"antd-dayjs-webpack-plugin": "^0.0.7",
|
||||||
|
"axios": "^0.19.0",
|
||||||
|
"babel-plugin-import": "^1.12.2",
|
||||||
|
"bizcharts": "^3.5.6",
|
||||||
|
"customize-cra": "^0.9.1",
|
||||||
|
"js-cookie": "^2.2.1",
|
||||||
|
"less": "^3.10.3",
|
||||||
|
"less-loader": "^5.0.0",
|
||||||
|
"mobx": "^5.15.0",
|
||||||
|
"mobx-react": "^6.1.4",
|
||||||
|
"react": "^16.12.0",
|
||||||
|
"react-app-rewired": "^2.1.5",
|
||||||
|
"react-color": "^2.17.3",
|
||||||
|
"react-dom": "^16.12.0",
|
||||||
|
"react-intl": "^3.9.3",
|
||||||
|
"react-loadable": "^5.5.0",
|
||||||
|
"react-responsive": "^8.0.1",
|
||||||
|
"react-router-dom": "^5.1.2",
|
||||||
|
"react-scripts": "3.2.0",
|
||||||
|
"typescript": "^3.7.4"
|
||||||
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
|
"start": "react-app-rewired start",
|
||||||
"start": "npm run dev",
|
"build": "react-app-rewired build",
|
||||||
"build": "node build/build.js"
|
"test": "react-app-rewired test",
|
||||||
|
"sm": "concurrently \"yarn start\" \"yarn run mock\" ",
|
||||||
|
"mock": "cd mocks && node ./server.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"eslintConfig": {
|
||||||
"axios": "0.17.1",
|
"extends": "react-app"
|
||||||
"element-ui": "^2.11.1",
|
|
||||||
"js-cookie": "2.2.0",
|
|
||||||
"mavon-editor": "^2.7.5",
|
|
||||||
"vue": "^2.6.10",
|
|
||||||
"vue-i18n": "^8.11.2",
|
|
||||||
"vue-router": "^3.0.3",
|
|
||||||
"vuex": "^3.1.1"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"browserslist": {
|
||||||
"autoprefixer": "^7.1.2",
|
"production": [
|
||||||
"babel-core": "^6.22.1",
|
">0.2%",
|
||||||
"babel-helper-vue-jsx-merge-props": "^2.0.3",
|
"not dead",
|
||||||
"babel-loader": "^7.1.1",
|
"not op_mini all"
|
||||||
"babel-plugin-syntax-jsx": "^6.18.0",
|
],
|
||||||
"babel-plugin-transform-runtime": "^6.22.0",
|
"development": [
|
||||||
"babel-plugin-transform-vue-jsx": "^3.5.0",
|
"last 1 chrome version",
|
||||||
"babel-preset-env": "^1.3.2",
|
"last 1 firefox version",
|
||||||
"babel-preset-stage-2": "^6.22.0",
|
"last 1 safari version"
|
||||||
"chalk": "^2.0.1",
|
]
|
||||||
"copy-webpack-plugin": "^4.0.1",
|
|
||||||
"css-loader": "^0.23.1",
|
|
||||||
"extract-text-webpack-plugin": "^3.0.0",
|
|
||||||
"file-loader": "^1.1.4",
|
|
||||||
"friendly-errors-webpack-plugin": "^1.6.1",
|
|
||||||
"html-loader": "^0.3.0",
|
|
||||||
"html-webpack-plugin": "^2.30.1",
|
|
||||||
"less": "^2.7.1",
|
|
||||||
"less-loader": "^2.2.3",
|
|
||||||
"node-notifier": "^5.1.2",
|
|
||||||
"optimize-css-assets-webpack-plugin": "^3.2.0",
|
|
||||||
"ora": "^1.2.0",
|
|
||||||
"portfinder": "^1.0.13",
|
|
||||||
"postcss-import": "^11.0.0",
|
|
||||||
"postcss-loader": "^2.0.8",
|
|
||||||
"postcss-url": "^7.2.1",
|
|
||||||
"rimraf": "^2.6.0",
|
|
||||||
"semver": "^5.3.0",
|
|
||||||
"shelljs": "^0.7.6",
|
|
||||||
"style-loader": "^0.13.1",
|
|
||||||
"uglifyjs-webpack-plugin": "^1.1.1",
|
|
||||||
"url-loader": "^0.5.8",
|
|
||||||
"vue-loader": "^13.3.0",
|
|
||||||
"vue-style-loader": "^3.0.1",
|
|
||||||
"vue-template-compiler": "^2.6.10",
|
|
||||||
"webpack": "^3.6.0",
|
|
||||||
"webpack-bundle-analyzer": "^2.9.0",
|
|
||||||
"webpack-dev-server": "^2.9.1",
|
|
||||||
"webpack-merge": "^4.1.0"
|
|
||||||
},
|
},
|
||||||
"engines": {
|
"devDependencies": {
|
||||||
"node": ">= 6.0.0",
|
"@babel/plugin-proposal-decorators": "^7.7.4",
|
||||||
"npm": ">= 3.0.0"
|
"antd-theme-webpack-plugin": "^1.3.0",
|
||||||
|
"babel-eslint": "^10.0.3",
|
||||||
|
"concurrently": "^5.0.0",
|
||||||
|
"eslint": "^6.7.2",
|
||||||
|
"eslint-plugin-react": "^7.14.3",
|
||||||
|
"eslint-plugin-react-hooks": "^2.0.1",
|
||||||
|
"json-server": "^0.15.1",
|
||||||
|
"mockjs": "^1.0.1-beta3"
|
||||||
},
|
},
|
||||||
"browserslist": [
|
"proxy": "http://localhost:3023"
|
||||||
"> 1%",
|
|
||||||
"last 2 versions",
|
|
||||||
"not ie <= 8"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
After Width: | Height: | Size: 22 KiB |
@ -0,0 +1,51 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<meta name="description" content="Web site created using create-react-app"/>
|
||||||
|
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||||
|
<link rel="apple-touch-icon" href="logo192.png" />
|
||||||
|
|
||||||
|
<title>React App</title>
|
||||||
|
<script>
|
||||||
|
window.less = {
|
||||||
|
async: false,
|
||||||
|
env: 'development'//production development
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<link rel="stylesheet/less" type="text/css" href="/color.less" />
|
||||||
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||||
|
<div id="root"></div>
|
||||||
|
<script type="text/javascript" src="/less.min.js"></script>
|
||||||
|
|
||||||
|
<!-- <script>
|
||||||
|
var userAgent = navigator.userAgent; //取得浏览器的userAgent字符串
|
||||||
|
var isOpera = userAgent.indexOf("Opera") > -1;
|
||||||
|
console.log(userAgent)
|
||||||
|
//判断是否Opera浏览器
|
||||||
|
if (isOpera) {
|
||||||
|
console.log("Opera");
|
||||||
|
};
|
||||||
|
//判断是否Firefox浏览器
|
||||||
|
if (userAgent.indexOf("Firefox") > -1) {
|
||||||
|
console.log("FF");
|
||||||
|
}
|
||||||
|
//判断是否Chrome浏览器
|
||||||
|
if (userAgent.indexOf("Chrome") > -1){
|
||||||
|
console.log("Chrome");
|
||||||
|
}
|
||||||
|
//判断是否Safari浏览器
|
||||||
|
if (userAgent.indexOf("Safari") > -1) {
|
||||||
|
console.log("Safari");
|
||||||
|
}
|
||||||
|
//判断是否IE浏览器
|
||||||
|
if (!!window.ActiveXObject || "ActiveXObject" in window) {
|
||||||
|
console.log("IE");
|
||||||
|
};
|
||||||
|
</script> -->
|
||||||
|
</body>
|
||||||
|
</html>
|
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 8.4 KiB |
After Width: | Height: | Size: 22 KiB |
@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"short_name": "React App",
|
||||||
|
"name": "Create React App Sample",
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"src": "favicon.ico",
|
||||||
|
"sizes": "64x64 32x32 24x24 16x16",
|
||||||
|
"type": "image/x-icon"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "logo192.png",
|
||||||
|
"type": "image/png",
|
||||||
|
"sizes": "192x192"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "logo512.png",
|
||||||
|
"type": "image/png",
|
||||||
|
"sizes": "512x512"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"start_url": ".",
|
||||||
|
"display": "standalone",
|
||||||
|
"theme_color": "#000000",
|
||||||
|
"background_color": "#ffffff"
|
||||||
|
}
|
@ -0,0 +1,2 @@
|
|||||||
|
# https://www.robotstxt.org/robotstxt.html
|
||||||
|
User-agent: *
|
@ -0,0 +1,21 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import { ConfigProvider } from 'antd'
|
||||||
|
import { inject, observer } from 'mobx-react'
|
||||||
|
import zhCN from 'antd/es/locale/zh_CN'
|
||||||
|
import enGB from 'antd/es/locale/en_GB'
|
||||||
|
|
||||||
|
const Config = inject('system')(observer((props) =>{
|
||||||
|
let {system} = props
|
||||||
|
let antdLocale = {}
|
||||||
|
antdLocale['zh_CN'] = zhCN
|
||||||
|
antdLocale['en_GB'] = enGB
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ConfigProvider locale={antdLocale[system.locale]}>
|
||||||
|
{props.children}
|
||||||
|
</ConfigProvider>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}))
|
||||||
|
|
||||||
|
export default Config
|
@ -0,0 +1,19 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import { inject, observer } from 'mobx-react'
|
||||||
|
import { IntlProvider } from 'react-intl' /* react-intl imports */
|
||||||
|
|
||||||
|
import locale from '@library/locale'
|
||||||
|
|
||||||
|
const Intl = inject('system')(observer((props) =>{
|
||||||
|
let {system} = props
|
||||||
|
let messages = locale
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<IntlProvider locale={system.locale.split('_')[0]} messages={messages[system.locale.split('_')[0]]}>
|
||||||
|
{props.children}
|
||||||
|
</IntlProvider>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}))
|
||||||
|
|
||||||
|
export default Intl
|
@ -0,0 +1,31 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import { Icon } from 'antd'
|
||||||
|
import { inject, observer } from 'mobx-react'
|
||||||
|
import style from './index.module.less'
|
||||||
|
const Languages = inject('system')(observer((props) =>{
|
||||||
|
let {system} = props
|
||||||
|
|
||||||
|
const IconFont = Icon.createFromIconfontCN({
|
||||||
|
scriptUrl: '//at.alicdn.com/t/font_1585712_tvew52du1cn.js'
|
||||||
|
})
|
||||||
|
|
||||||
|
function setLocale(locale){
|
||||||
|
system.setLocale(locale)
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className={style.languages}>
|
||||||
|
<div onClick={()=>{setLocale('en_GB')}}>
|
||||||
|
<IconFont type="icon-yingguo" className={`${style.icon}` } />
|
||||||
|
<div className={`${system.locale === 'en_GB'?style.selected:''}`}></div>
|
||||||
|
</div>
|
||||||
|
<div onClick={()=>{setLocale('zh_CN')}}>
|
||||||
|
<IconFont type="icon-china" className={`${style.icon}`} />
|
||||||
|
<div className={`${system.locale === 'zh_CN'?style.selected:''}`}></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}))
|
||||||
|
|
||||||
|
export default Languages
|
@ -0,0 +1,33 @@
|
|||||||
|
@import '../../styles/main.less';
|
||||||
|
|
||||||
|
.languages{
|
||||||
|
display: flex;
|
||||||
|
&>div{
|
||||||
|
position: relative;
|
||||||
|
cursor: pointer;
|
||||||
|
box-shadow: 0px 0px 4px 1px rgba(220, 223, 225, 0.5);
|
||||||
|
width: 28px;
|
||||||
|
height: 28px;
|
||||||
|
margin-right: 14px;
|
||||||
|
border-radius: 50%;
|
||||||
|
transition: all .2s;
|
||||||
|
}
|
||||||
|
&>div:hover{
|
||||||
|
transform: scale(1.3);
|
||||||
|
}
|
||||||
|
&>div:last-child{
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
.selected{
|
||||||
|
position: absolute;
|
||||||
|
top: 6%;
|
||||||
|
left: 6%;
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.icon{
|
||||||
|
font-size: 28px;
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import ReactDOM from 'react-dom'
|
||||||
|
import * as serviceWorker from './serviceWorker'
|
||||||
|
import App from './pages/App'
|
||||||
|
import { BrowserRouter as Router} from 'react-router-dom'
|
||||||
|
import { Provider } from 'mobx-react'
|
||||||
|
import stores from './store'
|
||||||
|
|
||||||
|
ReactDOM.render(
|
||||||
|
<Router>
|
||||||
|
<Provider {...stores}>
|
||||||
|
<App />
|
||||||
|
</Provider>
|
||||||
|
</Router>
|
||||||
|
, document.getElementById('root'))
|
||||||
|
|
||||||
|
serviceWorker.unregister()
|
@ -0,0 +1,33 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import { useLocation } from 'react-router-dom'
|
||||||
|
import { Breadcrumb } from 'antd'
|
||||||
|
import style from './index.module.less'
|
||||||
|
import { inject, observer } from 'mobx-react'
|
||||||
|
import { FormattedMessage as Message } from 'react-intl'
|
||||||
|
|
||||||
|
const BreadcrumbWrapper = inject('system')(observer((props) =>{
|
||||||
|
let {system} = props
|
||||||
|
let location = useLocation()
|
||||||
|
let pathname = location.pathname.split('/')
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className={`${style.breadcrumb}`}>
|
||||||
|
<div>{<Message id={pathname[pathname.length-1]}/>}</div>
|
||||||
|
<Breadcrumb separator=">">
|
||||||
|
{
|
||||||
|
pathname.map((item, key)=>{
|
||||||
|
if(item.length > 0){
|
||||||
|
return (
|
||||||
|
<Breadcrumb.Item key={key}><Message id={item}/></Breadcrumb.Item>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</Breadcrumb>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}))
|
||||||
|
|
||||||
|
export default BreadcrumbWrapper
|
@ -0,0 +1,7 @@
|
|||||||
|
@import '../../styles/main.less';
|
||||||
|
|
||||||
|
.breadcrumb{
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 6px 20px;
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
import React, { Suspense, useState, useEffect } from 'react'
|
||||||
|
import { Layout, BackTop } from 'antd'
|
||||||
|
import BreadcrumbWrapper from '@layouts/Breadcrumb'
|
||||||
|
import { Route } from 'react-router-dom'
|
||||||
|
import { isEmpty } from '@library/utils/validate'
|
||||||
|
const { Content } = Layout
|
||||||
|
// import {
|
||||||
|
// TransitionGroup,
|
||||||
|
// CSSTransition
|
||||||
|
// } from "react-transition-group";
|
||||||
|
function ContentWrapper(porps){
|
||||||
|
let { routers } = porps
|
||||||
|
let [routeItem, setRouteItem] = useState([])
|
||||||
|
|
||||||
|
useEffect( () => {
|
||||||
|
let item = []
|
||||||
|
routers.map((route) => {
|
||||||
|
if(!isEmpty(route.children)){
|
||||||
|
route.children.map((r) => {
|
||||||
|
item.push(r)
|
||||||
|
return ''
|
||||||
|
})
|
||||||
|
}else{
|
||||||
|
item.push(route)
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
})
|
||||||
|
setRouteItem(item)
|
||||||
|
return ()=>{
|
||||||
|
setRouteItem([])
|
||||||
|
}
|
||||||
|
}, [routers])
|
||||||
|
return(
|
||||||
|
<>
|
||||||
|
<Content>
|
||||||
|
<Suspense fallback={<div></div>}>
|
||||||
|
<BreadcrumbWrapper />
|
||||||
|
{
|
||||||
|
routeItem.map((route, key) => {
|
||||||
|
return(
|
||||||
|
<Route key={`${key}`} path={route.path} component={route.component}/>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
{/* <Route path="/home/*" component={Error404} /> */}
|
||||||
|
</Suspense>
|
||||||
|
<BackTop />
|
||||||
|
</Content>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ContentWrapper
|
@ -0,0 +1,56 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import { Drawer, Row, Switch } from 'antd'
|
||||||
|
import { inject, observer } from 'mobx-react'
|
||||||
|
import style from './index.module.less'
|
||||||
|
import { CirclePicker } from 'react-color'
|
||||||
|
import { modifyVars } from '@library/utils/modifyVars'
|
||||||
|
import Languages from '@components/Languages'
|
||||||
|
import { FormattedMessage as Message } from 'react-intl'
|
||||||
|
|
||||||
|
const DrawerWrapper = inject('system')(observer((props) =>{
|
||||||
|
let {system} = props
|
||||||
|
let primary = (color)=>{
|
||||||
|
system.setPrimary(color.hex)
|
||||||
|
modifyVars(system.dark, color.hex)
|
||||||
|
// modifyVars({'@primary-color': color.hex})
|
||||||
|
}
|
||||||
|
let dark = ()=>{
|
||||||
|
system.setDark()
|
||||||
|
modifyVars(system.dark, system.primary)
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div>
|
||||||
|
<Drawer
|
||||||
|
title={<Message id='setting'/>}
|
||||||
|
width={380}
|
||||||
|
onClose={system.setDrawer}
|
||||||
|
visible={system.drawer}
|
||||||
|
bodyStyle={{ paddingBottom: 80 }}
|
||||||
|
className={`${style.drawer} ${system.dark?style.dark:''}`}
|
||||||
|
>
|
||||||
|
<Row>
|
||||||
|
<div className={style.row}>
|
||||||
|
<div><Message id='model'/></div>
|
||||||
|
<div><Switch defaultChecked onClick={ dark } /></div>
|
||||||
|
</div>
|
||||||
|
<div className={style.row}>
|
||||||
|
<div><Message id='themes'/></div>
|
||||||
|
<div>
|
||||||
|
<CirclePicker color={system.primary} onChangeComplete={ primary }/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={style.row}>
|
||||||
|
<div><Message id='languages'/></div>
|
||||||
|
<div>
|
||||||
|
<Languages />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Row>
|
||||||
|
</Drawer>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}))
|
||||||
|
|
||||||
|
export default DrawerWrapper
|
@ -0,0 +1,28 @@
|
|||||||
|
@import '../../styles/main.less';
|
||||||
|
|
||||||
|
.drawer{
|
||||||
|
:global {
|
||||||
|
.ant-col{
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.row {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
.column {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.title {
|
||||||
|
font-size: 16px;
|
||||||
|
color: #3b4859;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.sub_title {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #8998ac;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,87 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import { Layout, Icon, Badge, Avatar, Popover } from 'antd'
|
||||||
|
import { useHistory } from 'react-router-dom'
|
||||||
|
import { inject, observer } from 'mobx-react'
|
||||||
|
import { useMediaQuery } from 'react-responsive'
|
||||||
|
import { removeToken } from '@utils/auth'
|
||||||
|
import style from './index.module.less'
|
||||||
|
const { Header } = Layout
|
||||||
|
|
||||||
|
const HeaderWrapper = inject('system', 'user')(observer((props) =>{
|
||||||
|
let history = useHistory()
|
||||||
|
let {system, user} = props
|
||||||
|
|
||||||
|
const isMobile = useMediaQuery({
|
||||||
|
query: '(max-device-width: 991px)'
|
||||||
|
})
|
||||||
|
|
||||||
|
const onClickLogout = ()=>{
|
||||||
|
removeToken()
|
||||||
|
history.push('/login')
|
||||||
|
}
|
||||||
|
const userPopover = (
|
||||||
|
<div className={style.userPopover}>
|
||||||
|
<div onClick={onClickLogout}><Icon type="logout" /><span>退出</span></div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
const messagePopover = (
|
||||||
|
<div className={style.messagePopover}>
|
||||||
|
<div>ss</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Header>
|
||||||
|
{
|
||||||
|
isMobile ?
|
||||||
|
<>dsa</>
|
||||||
|
:
|
||||||
|
<div className={style.header}>
|
||||||
|
<div>
|
||||||
|
<Icon type={system.collapsed?'menu-unfold':'menu-fold'} className={style.menu_icon} onClick={()=>{system.setCollapsed()}} />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
{/* <AutoComplete
|
||||||
|
className="certain-category-search"
|
||||||
|
dropdownClassName="certain-category-search-dropdown"
|
||||||
|
dropdownMatchSelectWidth={false}
|
||||||
|
dropdownStyle={{ width: 300 }}
|
||||||
|
size="large"
|
||||||
|
style={{ width: '100%' }}
|
||||||
|
placeholder="input here"
|
||||||
|
optionLabelProp="value"
|
||||||
|
>
|
||||||
|
<Input suffix={<Icon type="search" className={`${style.icon}`} />} />
|
||||||
|
</AutoComplete> */}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<Badge dot>
|
||||||
|
<Popover placement="bottomRight" content={messagePopover}>
|
||||||
|
<Icon type="bell" className={style.icon} />
|
||||||
|
</Popover>
|
||||||
|
</Badge>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<Popover className={`${style.pointer}`} placement="bottomRight" content={userPopover}>
|
||||||
|
<Badge dot>
|
||||||
|
<Avatar icon="user" src={user.info.get('avatar')}/>
|
||||||
|
</Badge>
|
||||||
|
</Popover>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<Icon type="align-left" className={style.icon} onClick={()=>{system.setDrawer()}} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</Header>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}))
|
||||||
|
|
||||||
|
export default HeaderWrapper
|
@ -0,0 +1,56 @@
|
|||||||
|
@import '../../styles/main.less';
|
||||||
|
|
||||||
|
.header{
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
box-sizing: border-box;
|
||||||
|
&>div{
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
&>div{
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 64px;
|
||||||
|
width: 50px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.menu_icon{
|
||||||
|
display: block;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
.icon{
|
||||||
|
display: block;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.plummer{
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.pointer{
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.messagePopover{
|
||||||
|
width: 400px;
|
||||||
|
}
|
||||||
|
.userPopover{
|
||||||
|
width: 200px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
&>div{
|
||||||
|
width: 100%;
|
||||||
|
height: 48px;
|
||||||
|
line-height: 48px;
|
||||||
|
cursor: pointer;
|
||||||
|
& > i{
|
||||||
|
margin-right: 6px;
|
||||||
|
}
|
||||||
|
&:hover{
|
||||||
|
&>span, &>i{
|
||||||
|
color: @dropdown-selected-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import { Icon } from 'antd'
|
||||||
|
import style from './index.module.less'
|
||||||
|
import { inject, observer } from 'mobx-react'
|
||||||
|
|
||||||
|
let Logo = inject('system')(observer((props) => {
|
||||||
|
let {system} = props
|
||||||
|
return(
|
||||||
|
<div className={style.logo}>
|
||||||
|
{/* ${display?style.title:style.title_hidden} */}
|
||||||
|
<div>
|
||||||
|
dsa
|
||||||
|
</div>
|
||||||
|
<div onClick={()=>{system.setCollapsed()}} className={`${style.icon} ${system.collapsed?style.icon_transition:''}`}>
|
||||||
|
<Icon type="menu-unfold" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}))
|
||||||
|
|
||||||
|
export default Logo
|
@ -0,0 +1,33 @@
|
|||||||
|
.logo{
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
font-size: 18px;
|
||||||
|
&>div{
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.title{
|
||||||
|
flex: 1;
|
||||||
|
font-weight:900;
|
||||||
|
color: #3B4859;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding-left: 19px;
|
||||||
|
&>span:first-of-type{
|
||||||
|
color: #3B7CFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.title_hidden{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.icon{
|
||||||
|
height: 64px;
|
||||||
|
width:64px;
|
||||||
|
justify-content: center;
|
||||||
|
transform: rotate(180deg);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.icon_transition{
|
||||||
|
transform: rotate(0);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,70 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import { useLocation } from 'react-router-dom'
|
||||||
|
import { Menu, Icon } from 'antd'
|
||||||
|
import { Link } from 'react-router-dom'
|
||||||
|
import { inject, observer } from 'mobx-react'
|
||||||
|
import { isEmpty } from '@library/utils/validate'
|
||||||
|
import style from './index.module.less'
|
||||||
|
import { FormattedMessage as Message } from 'react-intl'
|
||||||
|
const { SubMenu } = Menu
|
||||||
|
const MenuWrapper = inject('system')(observer((props) =>{
|
||||||
|
let {system, routers} = props
|
||||||
|
let location = useLocation()
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className={style.menu}>
|
||||||
|
<div className={style.logo}>
|
||||||
|
</div>
|
||||||
|
<Menu
|
||||||
|
mode={`${system.collapsed ? 'vertical' : 'inline'}`}
|
||||||
|
theme={`${system.theme}`}
|
||||||
|
selectedKeys={[location.pathname]}
|
||||||
|
forceSubMenuRender={true}
|
||||||
|
>
|
||||||
|
{
|
||||||
|
routers.map((route) => {
|
||||||
|
if(isEmpty(route.children)){
|
||||||
|
return (
|
||||||
|
<Menu.Item key={`${route.path}`}>
|
||||||
|
<Link to={route.path}>
|
||||||
|
<Icon type={route.icon}/>
|
||||||
|
<span><Message id={route.title}/></span>
|
||||||
|
</Link>
|
||||||
|
</Menu.Item>
|
||||||
|
)
|
||||||
|
}else{
|
||||||
|
let items = []
|
||||||
|
route.children.map((r) => {
|
||||||
|
items.push(
|
||||||
|
<Menu.Item key={r.path}>
|
||||||
|
<Link to={r.path}>
|
||||||
|
{
|
||||||
|
isEmpty(r.icon)?'':<Icon type={r.icon}/>
|
||||||
|
}
|
||||||
|
<span><Message id={r.title}/></span>
|
||||||
|
</Link>
|
||||||
|
</Menu.Item>
|
||||||
|
)
|
||||||
|
return ''
|
||||||
|
})
|
||||||
|
return (
|
||||||
|
<SubMenu key={`${route.path}`} title={
|
||||||
|
<span>
|
||||||
|
<Icon type={route.icon} />
|
||||||
|
<span><Message id={route.title}/></span>
|
||||||
|
</span>
|
||||||
|
}>
|
||||||
|
{items}
|
||||||
|
</SubMenu>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</Menu>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}))
|
||||||
|
|
||||||
|
export default MenuWrapper
|
@ -0,0 +1,7 @@
|
|||||||
|
.menu{
|
||||||
|
.logo{
|
||||||
|
height: 32px;
|
||||||
|
background: #aaa;
|
||||||
|
margin: 16px;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
import Layout from '@/layouts/Layout'
|
||||||
|
export {
|
||||||
|
Layout
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
const enUS = {
|
||||||
|
home: 'Home',
|
||||||
|
dashboard: 'Dashboard',
|
||||||
|
chart: 'Chart',
|
||||||
|
charts: 'Charts',
|
||||||
|
element: 'Element',
|
||||||
|
icons: 'Icons',
|
||||||
|
accordion: 'Accordion',
|
||||||
|
paginations: 'Paginations',
|
||||||
|
datePickers: 'DatePickers',
|
||||||
|
setting: 'Setting',
|
||||||
|
themes: 'Themes',
|
||||||
|
model: 'Model',
|
||||||
|
languages: 'Languages'
|
||||||
|
}
|
||||||
|
export default enUS
|
@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
import zhCN from '@library/locale/zh_CN' // 中文
|
||||||
|
import enUS from '@library/locale/en_US' // 英文
|
||||||
|
|
||||||
|
export default {
|
||||||
|
'en': enUS,
|
||||||
|
'zh': zhCN
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
const zhCN = {
|
||||||
|
home: '主页',
|
||||||
|
dashboard: '仪表盘',
|
||||||
|
chart: '图表',
|
||||||
|
charts: '图表',
|
||||||
|
element: '元素',
|
||||||
|
icons: '图标',
|
||||||
|
accordion: '手风琴',
|
||||||
|
paginations: '页码',
|
||||||
|
datePickers: '时间',
|
||||||
|
setting: '设置',
|
||||||
|
themes: '主题',
|
||||||
|
model: '模式',
|
||||||
|
languages: '语言'
|
||||||
|
}
|
||||||
|
export default zhCN
|
@ -0,0 +1,28 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import Element from '@library/routes/modules/Element'
|
||||||
|
|
||||||
|
const Dashboard = React.lazy(() => import('@pages/Index/Dashboard'))
|
||||||
|
const Charts = React.lazy(() => import('@pages/Index/Charts'))
|
||||||
|
|
||||||
|
const Routers = [
|
||||||
|
{
|
||||||
|
path: '/home/dashboard',
|
||||||
|
title: 'dashboard',
|
||||||
|
icon: 'dashboard',
|
||||||
|
component: Dashboard
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/home/charts',
|
||||||
|
title: 'chart',
|
||||||
|
icon: 'pie-chart',
|
||||||
|
component: Charts
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/home/element',
|
||||||
|
title: 'element',
|
||||||
|
icon: 'build',
|
||||||
|
children: Element
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
export default Routers
|
@ -0,0 +1,19 @@
|
|||||||
|
import React from 'react'
|
||||||
|
const A = React.lazy(() => import('@pages/Index/Demo/A'))
|
||||||
|
const B = React.lazy(() => import('@pages/Index/Demo/B'))
|
||||||
|
|
||||||
|
const Demo = [
|
||||||
|
{
|
||||||
|
path: '/a',
|
||||||
|
title: 'A',
|
||||||
|
icon: 'bar-chart',
|
||||||
|
component: A
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/b',
|
||||||
|
title: 'B',
|
||||||
|
icon: 'bar-chart',
|
||||||
|
component: B
|
||||||
|
}
|
||||||
|
]
|
||||||
|
export default Demo
|
@ -0,0 +1,34 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
const Accordion = React.lazy(() => import('@pages/Index/Elements/Accordion'))
|
||||||
|
const Paginations = React.lazy(() => import('@pages/Index/Elements/Paginations'))
|
||||||
|
const DatePickers = React.lazy(() => import('@pages/Index/Elements/DatePickers'))
|
||||||
|
const Icons = React.lazy(() => import('@pages/Index/Elements/Icons'))
|
||||||
|
|
||||||
|
const Demo = [
|
||||||
|
{
|
||||||
|
path: '/home/element/accordion',
|
||||||
|
title: 'accordion',
|
||||||
|
icon: 'pic-center',
|
||||||
|
component: Accordion
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/home/element/paginations',
|
||||||
|
title: 'paginations',
|
||||||
|
icon: 'pic-center',
|
||||||
|
component: Paginations
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/home/element/datePickers',
|
||||||
|
title: 'datePickers',
|
||||||
|
icon: 'calendar',
|
||||||
|
component: DatePickers
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/home/element/icons',
|
||||||
|
title: 'icons',
|
||||||
|
icon: 'smile',
|
||||||
|
component: Icons
|
||||||
|
}
|
||||||
|
]
|
||||||
|
export default Demo
|
@ -0,0 +1,15 @@
|
|||||||
|
import Cookies from 'js-cookie'
|
||||||
|
|
||||||
|
const TokenKey = 'admin-token'
|
||||||
|
|
||||||
|
export function getToken() {
|
||||||
|
return Cookies.get(TokenKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setToken(token) {
|
||||||
|
return Cookies.set(TokenKey, token)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function removeToken() {
|
||||||
|
return Cookies.remove(TokenKey)
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
import axios from 'axios'
|
||||||
|
|
||||||
|
if (process.env.NODE_ENV === 'production') {
|
||||||
|
axios.defaults.baseURL = 'https://www.baidu.com'
|
||||||
|
}else{
|
||||||
|
axios.defaults.baseURL = 'https://www.production.com'
|
||||||
|
}
|
||||||
|
|
||||||
|
let loadingInstance = null //这里是loading
|
||||||
|
//使用create方法创建axios实例
|
||||||
|
export const Service = axios.create({
|
||||||
|
timeout: 7000, // 请求超时时间
|
||||||
|
method: 'post',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json;charset=UTF-8'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// 添加请求拦截器
|
||||||
|
Service.interceptors.request.use(config => {
|
||||||
|
return config
|
||||||
|
})
|
||||||
|
// 添加响应拦截器
|
||||||
|
Service.interceptors.response.use(response => {
|
||||||
|
loadingInstance.close()
|
||||||
|
// console.log(response)
|
||||||
|
return response.data
|
||||||
|
}, error => {
|
||||||
|
return Promise.reject(error)
|
||||||
|
})
|
@ -0,0 +1,13 @@
|
|||||||
|
let adminKey = 'admin-'
|
||||||
|
const storage = {
|
||||||
|
set(key, value){
|
||||||
|
localStorage.setItem(adminKey+key, JSON.stringify(value))
|
||||||
|
},
|
||||||
|
get(key){
|
||||||
|
return JSON.parse(localStorage.getItem(adminKey+key))
|
||||||
|
},
|
||||||
|
remove(key){
|
||||||
|
localStorage.removeItem(adminKey+key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export default storage
|
@ -0,0 +1,18 @@
|
|||||||
|
import {Light, Dark} from '@styles/theme'
|
||||||
|
|
||||||
|
export function modifyVars(model, primary){
|
||||||
|
//window.less.modifyVars(vars)
|
||||||
|
if(model){
|
||||||
|
window.less.modifyVars(Dark(primary))
|
||||||
|
}else{
|
||||||
|
window.less.modifyVars(Light(primary))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// export function modifyModel(model){
|
||||||
|
// // let {dark, light} = theme
|
||||||
|
// // let dark = Dark
|
||||||
|
// // console.log(Dark())
|
||||||
|
// // console.log(Light())
|
||||||
|
|
||||||
|
// }
|
@ -0,0 +1,16 @@
|
|||||||
|
/**
|
||||||
|
* 判断是否为空
|
||||||
|
* @param {*} value
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
export function isEmpty(value){
|
||||||
|
if(value === null || value === '' || value === 'undefined' || value === undefined || value === 'null' || value.length === 0){
|
||||||
|
return true
|
||||||
|
} else{
|
||||||
|
// value = value.replace(/\s/g, '')
|
||||||
|
// if(value === ''){
|
||||||
|
// return true
|
||||||
|
// }
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
import React, { useEffect } from 'react'
|
||||||
|
import {Route, Switch, Redirect} from 'react-router-dom'
|
||||||
|
import { modifyVars } from '../../library/utils/modifyVars'
|
||||||
|
import { inject, observer } from 'mobx-react'
|
||||||
|
import '@/styles/main.less'
|
||||||
|
import Home from '../../pages/Index'
|
||||||
|
import Login from '../../pages/Login'
|
||||||
|
import ConfigProvider from '../../components/ConfigProvider'
|
||||||
|
import Intl from '../../components/Intl'
|
||||||
|
|
||||||
|
|
||||||
|
let App = inject('system')(observer((props:any) => {
|
||||||
|
let {system} = props
|
||||||
|
//npm install --save rc-form-hooks
|
||||||
|
// https://www.jianshu.com/p/fc59cb61f7cc
|
||||||
|
useEffect(() => {
|
||||||
|
console.log("modify vars")
|
||||||
|
modifyVars(system.dark, system.primary)
|
||||||
|
return () => {}
|
||||||
|
})
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Intl>
|
||||||
|
<ConfigProvider>
|
||||||
|
<Switch>
|
||||||
|
<Route path="/home" component={Home} />
|
||||||
|
<Route path="/login" exact component={Login} />
|
||||||
|
<Redirect to="/home"/>
|
||||||
|
</Switch>
|
||||||
|
</ConfigProvider>
|
||||||
|
</Intl>
|
||||||
|
|
||||||
|
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}))
|
||||||
|
|
||||||
|
export default App
|
@ -0,0 +1,97 @@
|
|||||||
|
import React, { useState, useEffect} from 'react'
|
||||||
|
import { inject, observer } from 'mobx-react'
|
||||||
|
import { Spin, Row, Col, Card } from 'antd'
|
||||||
|
import {
|
||||||
|
Chart,
|
||||||
|
Geom,
|
||||||
|
Axis,
|
||||||
|
Tooltip
|
||||||
|
} from 'bizcharts'
|
||||||
|
|
||||||
|
const Dashboard = inject('system')(observer(() =>{
|
||||||
|
const [loading, setLoading] = useState(true)
|
||||||
|
useEffect(() => {
|
||||||
|
setLoading(false)
|
||||||
|
return () => {}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const data = [
|
||||||
|
{
|
||||||
|
year: '1991',
|
||||||
|
value: 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
year: '1992',
|
||||||
|
value: 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
year: '1993',
|
||||||
|
value: 3.5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
year: '1994',
|
||||||
|
value: 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
year: '1995',
|
||||||
|
value: 4.9
|
||||||
|
},
|
||||||
|
{
|
||||||
|
year: '1996',
|
||||||
|
value: 6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
year: '1997',
|
||||||
|
value: 7
|
||||||
|
},
|
||||||
|
{
|
||||||
|
year: '1998',
|
||||||
|
value: 9
|
||||||
|
},
|
||||||
|
{
|
||||||
|
year: '1999',
|
||||||
|
value: 13
|
||||||
|
}
|
||||||
|
]
|
||||||
|
const cols = {
|
||||||
|
value: {
|
||||||
|
min: 0
|
||||||
|
},
|
||||||
|
year: {
|
||||||
|
range: [0, 1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Spin spinning={loading} tip='Loading...'>
|
||||||
|
<div className='container'>
|
||||||
|
<Row gutter={24}>
|
||||||
|
<Col xs={24} sm={24} md={12} lg={12} xl={12} className='gutter-row'>
|
||||||
|
<Card style={{borderRadius:'10px'}}>
|
||||||
|
<Chart padding="auto" height={278} data={data} scale={cols} forceFit>
|
||||||
|
<Axis name='year' />
|
||||||
|
<Axis name='value' />
|
||||||
|
<Tooltip
|
||||||
|
crosshairs={{
|
||||||
|
type: 'y'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Geom type='line' position='year*value' size={2} />
|
||||||
|
<Geom
|
||||||
|
type='point'
|
||||||
|
position='year*value'
|
||||||
|
size={4}
|
||||||
|
shape={'circle'}
|
||||||
|
style={{
|
||||||
|
stroke: '#fff',
|
||||||
|
lineWidth: 1
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Chart>
|
||||||
|
</Card>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</div>
|
||||||
|
</Spin>
|
||||||
|
)
|
||||||
|
}))
|
||||||
|
export default Dashboard
|
@ -0,0 +1,20 @@
|
|||||||
|
import React, { useState, useEffect} from 'react'
|
||||||
|
import { inject, observer } from 'mobx-react'
|
||||||
|
import { Spin } from 'antd'
|
||||||
|
const A = inject('system')(observer(() =>{
|
||||||
|
|
||||||
|
const [loading, setLoading] = useState(true)
|
||||||
|
useEffect(() => {
|
||||||
|
setLoading(false)
|
||||||
|
return () => {}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Spin spinning={loading} tip="Loading...">
|
||||||
|
<div className='container'>
|
||||||
|
s
|
||||||
|
</div>
|
||||||
|
</Spin>
|
||||||
|
)
|
||||||
|
}))
|
||||||
|
export default A
|
@ -0,0 +1,94 @@
|
|||||||
|
import React, { useState, useEffect } from 'react'
|
||||||
|
import { Spin } from 'antd'
|
||||||
|
function B() {
|
||||||
|
const [loading, setLoading] = useState(true)
|
||||||
|
useEffect(() => {
|
||||||
|
setLoading(false)
|
||||||
|
return () => {}
|
||||||
|
}, [])
|
||||||
|
return (
|
||||||
|
<Spin spinning={loading} tip="Loading...">
|
||||||
|
<div>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
<p>ds</p>
|
||||||
|
</div>
|
||||||
|
</Spin>
|
||||||
|
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default B
|
@ -0,0 +1,19 @@
|
|||||||
|
import React, { useEffect, useState } from 'react'
|
||||||
|
import { Spin } from 'antd'
|
||||||
|
|
||||||
|
function DatePickers() {
|
||||||
|
const [loading, setLoading] = useState(true)
|
||||||
|
useEffect(() => {
|
||||||
|
setLoading(false)
|
||||||
|
return () => {}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Spin spinning={loading} tip="Loading...">
|
||||||
|
<div className='container'>
|
||||||
|
DatePicker
|
||||||
|
</div>
|
||||||
|
</Spin>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
export default DatePickers
|
@ -0,0 +1,19 @@
|
|||||||
|
import React, { useEffect, useState } from 'react'
|
||||||
|
import { Spin } from 'antd'
|
||||||
|
|
||||||
|
function Icons() {
|
||||||
|
const [loading, setLoading] = useState(true)
|
||||||
|
useEffect(() => {
|
||||||
|
setLoading(false)
|
||||||
|
return () => {}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Spin spinning={loading} tip="Loading...">
|
||||||
|
<div className='container'>
|
||||||
|
Icons
|
||||||
|
</div>
|
||||||
|
</Spin>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
export default Icons
|
@ -0,0 +1,49 @@
|
|||||||
|
import React, { useEffect } from 'react'
|
||||||
|
import { withRouter, useHistory } from 'react-router-dom'
|
||||||
|
import { Layout } from 'antd'
|
||||||
|
import { useMediaQuery } from 'react-responsive'
|
||||||
|
import style from './index.module.less'
|
||||||
|
import { inject, observer } from 'mobx-react'
|
||||||
|
import MenuWrapper from '../../layouts/Menu'
|
||||||
|
import DrawerWrapper from '../../layouts/Drawer'
|
||||||
|
import ContentWrapper from '../../layouts/Content'
|
||||||
|
import HeaderWrapper from '../../layouts/Header'
|
||||||
|
import { getToken } from '../../library/utils/auth'
|
||||||
|
import { isEmpty } from '../../library/utils/validate'
|
||||||
|
import Routers from '../../library/routes'
|
||||||
|
|
||||||
|
const { Sider } = Layout
|
||||||
|
|
||||||
|
let Index = inject('system')(observer((props:any) => {
|
||||||
|
let {system} = props
|
||||||
|
// const isMobile = useMediaQuery({
|
||||||
|
// query: '(max-device-width: 991px)'
|
||||||
|
// })
|
||||||
|
let history = useHistory()
|
||||||
|
useEffect(() => {
|
||||||
|
if(isEmpty(getToken())){
|
||||||
|
history.push('/login')
|
||||||
|
}
|
||||||
|
return () => {}
|
||||||
|
})
|
||||||
|
const isDesktop = useMediaQuery({
|
||||||
|
query: '(min-device-width: 992px)'
|
||||||
|
})
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Layout className={`${style.app} ${system.dark?style.dark:''}`}>
|
||||||
|
{isDesktop &&
|
||||||
|
<Sider collapsed={system.collapsed}>
|
||||||
|
<MenuWrapper routers={Routers}/>
|
||||||
|
</Sider>
|
||||||
|
}
|
||||||
|
<Layout>
|
||||||
|
<HeaderWrapper />
|
||||||
|
<ContentWrapper routers={Routers}/>
|
||||||
|
<DrawerWrapper />
|
||||||
|
</Layout>
|
||||||
|
</Layout>
|
||||||
|
)
|
||||||
|
}))
|
||||||
|
|
||||||
|
export default withRouter(Index)
|
@ -0,0 +1,105 @@
|
|||||||
|
import React, {useState} from 'react'
|
||||||
|
import { Button, Form, Input, Icon, message, Spin } from 'antd'
|
||||||
|
import { useHistory} from 'react-router-dom'
|
||||||
|
import style from './index.module.less'
|
||||||
|
import { post } from '@http/index'
|
||||||
|
import { setToken } from '@utils/auth'
|
||||||
|
import storage from '@utils/localStorage'
|
||||||
|
import { inject, observer } from 'mobx-react'
|
||||||
|
|
||||||
|
function FormBox(props) {
|
||||||
|
let { user } = props
|
||||||
|
let history = useHistory()
|
||||||
|
const [btnLoading, setBtnLoading] = useState(false)
|
||||||
|
const { getFieldDecorator } = props.form
|
||||||
|
function handleSubmit(e){
|
||||||
|
e.preventDefault()
|
||||||
|
props.form.validateFields((err, values) => {
|
||||||
|
setBtnLoading(true)
|
||||||
|
post('/api/login',
|
||||||
|
{
|
||||||
|
username:'admin',
|
||||||
|
password: '123456'
|
||||||
|
},
|
||||||
|
function(res){
|
||||||
|
if(res.err === 1){
|
||||||
|
message.error(res.msg)
|
||||||
|
}else{
|
||||||
|
setToken(res.data.token)
|
||||||
|
delete res.data.token
|
||||||
|
storage.set('info', res.data)
|
||||||
|
props.setloading(true)
|
||||||
|
user.setInfo(res.data)
|
||||||
|
setTimeout(() => {
|
||||||
|
props.setloading(false)
|
||||||
|
history.push('/home/dashboard')
|
||||||
|
}, 2000)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
function(err){
|
||||||
|
console.log(err)
|
||||||
|
message.error('ds')
|
||||||
|
},
|
||||||
|
function(){
|
||||||
|
setBtnLoading(false)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
// if (!err) {
|
||||||
|
// history.push("/index");
|
||||||
|
// }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Form className="login-form">
|
||||||
|
<Form.Item>
|
||||||
|
{getFieldDecorator('username', {
|
||||||
|
initialValue: 'dsa',
|
||||||
|
rules: [{ required: true, message: '用户名不能为空' }]
|
||||||
|
})(
|
||||||
|
<Input
|
||||||
|
prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.25)' }} />}
|
||||||
|
placeholder="Username"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item>
|
||||||
|
{getFieldDecorator('password', {
|
||||||
|
initialValue: 'dsa',
|
||||||
|
rules: [{ required: true, message: '密码不能为空' }]
|
||||||
|
})(
|
||||||
|
<Input.Password
|
||||||
|
prefix={<Icon type="lock" style={{ color: 'rgba(0,0,0,.25)' }} />}
|
||||||
|
type="password"
|
||||||
|
placeholder="Password"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item labelAlign='right' labelCol={{span: 3, offset: 12}}>
|
||||||
|
<Button onClick={handleSubmit} type="primary" shape="round" loading={btnLoading?true:false}>
|
||||||
|
登录
|
||||||
|
</Button>
|
||||||
|
</Form.Item>
|
||||||
|
</Form>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
const FormBoxWrapper = Form.create({ name: 'normal_login' })(inject('user')(observer(FormBox)))
|
||||||
|
|
||||||
|
let Login = inject('user')(observer(() => {
|
||||||
|
const [loading, setloading] = useState(false)
|
||||||
|
//npm install --save rc-form-hooks
|
||||||
|
// https://www.jianshu.com/p/fc59cb61f7cc
|
||||||
|
return (
|
||||||
|
<div className={style.app}>
|
||||||
|
<Spin spinning={loading}>
|
||||||
|
<div className={style.rectangle}>
|
||||||
|
<FormBoxWrapper setloading={setloading}/>
|
||||||
|
</div>
|
||||||
|
</Spin>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}))
|
||||||
|
|
||||||
|
export default Login
|
@ -0,0 +1,22 @@
|
|||||||
|
|
||||||
|
.app{
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
background: #f3f6f9;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
.rectangle{
|
||||||
|
width: 360px;
|
||||||
|
background-color: #ffffff;
|
||||||
|
box-shadow: 0px 2px 4px 0px
|
||||||
|
#d0d0d0;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
:global {
|
||||||
|
.ant-form-item{
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
/* eslint-disable react-hooks/rules-of-hooks */
|
||||||
|
import React from 'react'
|
||||||
|
import {Responsive, useMediaQuery} from 'react-responsive'
|
||||||
|
|
||||||
|
const Desktop = props => <Responsive {...props} minWidth={768} />
|
||||||
|
const Mobile = props => <Responsive {...props} maxWidth={767} />
|
||||||
|
const isMobile = useMediaQuery({
|
||||||
|
query: '(max-device-width: 991px)'
|
||||||
|
})
|
||||||
|
export {
|
||||||
|
Desktop,
|
||||||
|
Mobile,
|
||||||
|
isMobile
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
/// <reference types="react-scripts" />
|
@ -0,0 +1,135 @@
|
|||||||
|
// This optional code is used to register a service worker.
|
||||||
|
// register() is not called by default.
|
||||||
|
|
||||||
|
// This lets the app load faster on subsequent visits in production, and gives
|
||||||
|
// it offline capabilities. However, it also means that developers (and users)
|
||||||
|
// will only see deployed updates on subsequent visits to a page, after all the
|
||||||
|
// existing tabs open on the page have been closed, since previously cached
|
||||||
|
// resources are updated in the background.
|
||||||
|
|
||||||
|
// To learn more about the benefits of this model and instructions on how to
|
||||||
|
// opt-in, read https://bit.ly/CRA-PWA
|
||||||
|
/* eslint-disable */
|
||||||
|
const isLocalhost = Boolean(
|
||||||
|
window.location.hostname === 'localhost' ||
|
||||||
|
// [::1] is the IPv6 localhost address.
|
||||||
|
window.location.hostname === '[::1]' ||
|
||||||
|
// 127.0.0.1/8 is considered localhost for IPv4.
|
||||||
|
window.location.hostname.match(
|
||||||
|
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
export function register(config) {
|
||||||
|
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
|
||||||
|
// The URL constructor is available in all browsers that support SW.
|
||||||
|
const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
|
||||||
|
if (publicUrl.origin !== window.location.origin) {
|
||||||
|
// Our service worker won't work if PUBLIC_URL is on a different origin
|
||||||
|
// from what our page is served on. This might happen if a CDN is used to
|
||||||
|
// serve assets; see https://github.com/facebook/create-react-app/issues/2374
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('load', () => {
|
||||||
|
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
|
||||||
|
|
||||||
|
if (isLocalhost) {
|
||||||
|
// This is running on localhost. Let's check if a service worker still exists or not.
|
||||||
|
checkValidServiceWorker(swUrl, config);
|
||||||
|
|
||||||
|
// Add some additional logging to localhost, pointing developers to the
|
||||||
|
// service worker/PWA documentation.
|
||||||
|
navigator.serviceWorker.ready.then(() => {
|
||||||
|
console.log(
|
||||||
|
'This web app is being served cache-first by a service ' +
|
||||||
|
'worker. To learn more, visit https://bit.ly/CRA-PWA'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Is not localhost. Just register service worker
|
||||||
|
registerValidSW(swUrl, config);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function registerValidSW(swUrl, config) {
|
||||||
|
navigator.serviceWorker
|
||||||
|
.register(swUrl)
|
||||||
|
.then(registration => {
|
||||||
|
registration.onupdatefound = () => {
|
||||||
|
const installingWorker = registration.installing;
|
||||||
|
if (installingWorker == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
installingWorker.onstatechange = () => {
|
||||||
|
if (installingWorker.state === 'installed') {
|
||||||
|
if (navigator.serviceWorker.controller) {
|
||||||
|
// At this point, the updated precached content has been fetched,
|
||||||
|
// but the previous service worker will still serve the older
|
||||||
|
// content until all client tabs are closed.
|
||||||
|
console.log(
|
||||||
|
'New content is available and will be used when all ' +
|
||||||
|
'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Execute callback
|
||||||
|
if (config && config.onUpdate) {
|
||||||
|
config.onUpdate(registration);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// At this point, everything has been precached.
|
||||||
|
// It's the perfect time to display a
|
||||||
|
// "Content is cached for offline use." message.
|
||||||
|
console.log('Content is cached for offline use.');
|
||||||
|
|
||||||
|
// Execute callback
|
||||||
|
if (config && config.onSuccess) {
|
||||||
|
config.onSuccess(registration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Error during service worker registration:', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkValidServiceWorker(swUrl, config) {
|
||||||
|
// Check if the service worker can be found. If it can't reload the page.
|
||||||
|
fetch(swUrl)
|
||||||
|
.then(response => {
|
||||||
|
// Ensure service worker exists, and that we really are getting a JS file.
|
||||||
|
const contentType = response.headers.get('content-type');
|
||||||
|
if (
|
||||||
|
response.status === 404 ||
|
||||||
|
(contentType != null && contentType.indexOf('javascript') === -1)
|
||||||
|
) {
|
||||||
|
// No service worker found. Probably a different app. Reload the page.
|
||||||
|
navigator.serviceWorker.ready.then(registration => {
|
||||||
|
registration.unregister().then(() => {
|
||||||
|
window.location.reload();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Service worker found. Proceed as normal.
|
||||||
|
registerValidSW(swUrl, config);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
console.log(
|
||||||
|
'No internet connection found. App is running in offline mode.'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function unregister() {
|
||||||
|
if ('serviceWorker' in navigator) {
|
||||||
|
navigator.serviceWorker.ready.then(registration => {
|
||||||
|
registration.unregister();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -1,20 +1,7 @@
|
|||||||
import Vue from 'vue'
|
import system from './system'
|
||||||
import Vuex from 'vuex'
|
import user from './user'
|
||||||
import misc from './modules/misc'
|
|
||||||
import user from './modules/user'
|
|
||||||
import post from './modules/post'
|
|
||||||
import getters from './getters'
|
|
||||||
|
|
||||||
Vue.use(Vuex)
|
|
||||||
|
|
||||||
const store = new Vuex.Store({
|
|
||||||
modules: {
|
|
||||||
misc,
|
|
||||||
user,
|
|
||||||
post
|
|
||||||
},
|
|
||||||
getters
|
|
||||||
})
|
|
||||||
|
|
||||||
export default store
|
|
||||||
|
|
||||||
|
export default {
|
||||||
|
system,
|
||||||
|
user
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
import { observable, action } from 'mobx'
|
||||||
|
|
||||||
|
class System{
|
||||||
|
// constructor() {
|
||||||
|
|
||||||
|
// }
|
||||||
|
@observable dark = false
|
||||||
|
@observable collapsed = false
|
||||||
|
@observable drawer = false
|
||||||
|
@observable mode = 'inline'
|
||||||
|
@observable theme = 'light'
|
||||||
|
@observable primary = '#2196f3'
|
||||||
|
@observable locale = 'zh_CN'
|
||||||
|
@observable lang = 'zh'
|
||||||
|
|
||||||
|
@action
|
||||||
|
setDark = () => {
|
||||||
|
this.dark = !this.dark
|
||||||
|
if(this.dark){
|
||||||
|
this.theme = 'dark'
|
||||||
|
}else{
|
||||||
|
this.theme = 'light'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@action
|
||||||
|
setCollapsed = () => {
|
||||||
|
this.collapsed = !this.collapsed
|
||||||
|
}
|
||||||
|
@action
|
||||||
|
setDrawer = () => {
|
||||||
|
this.drawer = !this.drawer
|
||||||
|
}
|
||||||
|
@action
|
||||||
|
setPrimary = (color) => {
|
||||||
|
this.primary = color
|
||||||
|
}
|
||||||
|
@action
|
||||||
|
setLocale = (locale) => {
|
||||||
|
this.locale = locale
|
||||||
|
}
|
||||||
|
@action
|
||||||
|
setLang = (lang) => {
|
||||||
|
this.lang = lang
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default new System()
|
@ -0,0 +1,12 @@
|
|||||||
|
import { action, observable } from 'mobx'
|
||||||
|
|
||||||
|
class User{
|
||||||
|
@observable info = new Map()
|
||||||
|
|
||||||
|
@action
|
||||||
|
setInfo = (info) => {
|
||||||
|
this.info.replace(info)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default new User()
|
@ -0,0 +1,13 @@
|
|||||||
|
@import "./vars.less";
|
||||||
|
|
||||||
|
:global {
|
||||||
|
.ant-layout{
|
||||||
|
width: 100vw;
|
||||||
|
height: 100%;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
.container{
|
||||||
|
min-height: calc(~ '100vh - 64px - 33px');
|
||||||
|
padding: 20px 20px;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
/* eslint-disable quotes */
|
||||||
|
let colors = require('@ant-design/colors')
|
||||||
|
|
||||||
|
let darkTheme = {
|
||||||
|
'@primary-color': '#0A53B0',
|
||||||
|
'@layout-body-background': '#171717',
|
||||||
|
'@background-color-base': '#262626',
|
||||||
|
'@body-background': '#404041',
|
||||||
|
'@layout-sider-background': '#171F22',
|
||||||
|
'@component-background': '#171F22',
|
||||||
|
'@layout-header-background': '#171F22',
|
||||||
|
'@menu-dark-submenu-bg': '#171F22',
|
||||||
|
'@input-bg': '#313133',
|
||||||
|
'@btn-default-bg': '#262626',
|
||||||
|
'@border-color-base': 'rgba(255, 255, 255, 0.25)',
|
||||||
|
'@border-color-split': '#363636',
|
||||||
|
'@heading-color': '#E3E3E3',
|
||||||
|
'@text-color': '#E3E3E3',
|
||||||
|
'@text-color-secondary': 'fade(#fff, 65%)',
|
||||||
|
'@table-selected-row-bg': '#3a3a3a',
|
||||||
|
'@table-expanded-row-bg': '#3b3b3b',
|
||||||
|
'@table-header-bg': '#3a3a3b',
|
||||||
|
'@table-row-hover-bg': '#3a3a3b',
|
||||||
|
'@layout-trigger-color': 'fade(#fff, 80%)',
|
||||||
|
'@layout-trigger-background': '#313232',
|
||||||
|
'@alert-message-color': 'fade(#000, 67%)',
|
||||||
|
'@item-hover-bg': "fade(" + colors.blue[5] + ", 20%)",
|
||||||
|
'@item-active-bg': "fade(" + colors.blue[5] + ", 40%)",
|
||||||
|
'@disabled-color': 'rgba(255, 255, 255, 0.25)',
|
||||||
|
'@tag-default-bg': '#262628',
|
||||||
|
'@popover-bg': '#262629',
|
||||||
|
'@wait-icon-color': 'fade(#fff, 64%)',
|
||||||
|
'@background-color-light': "fade(" + colors.blue[5] + ", 40%)",
|
||||||
|
'@collapse-header-bg': '#262629',
|
||||||
|
'@info-color': '#313133',
|
||||||
|
'@highlight-color': colors.red[7],
|
||||||
|
'@warning-color': colors.gold[9],
|
||||||
|
'@menu-dark-highlight-color': "#fff"
|
||||||
|
}
|
||||||
|
export default darkTheme
|
@ -0,0 +1,27 @@
|
|||||||
|
|
||||||
|
import dark from './dark'
|
||||||
|
import light from './light'
|
||||||
|
|
||||||
|
const darkTheme = {}
|
||||||
|
const lightTheme = {}
|
||||||
|
|
||||||
|
let Light = (primary) => {
|
||||||
|
Object.keys(light).forEach((key) => {
|
||||||
|
lightTheme[`${key}`] = light[key]
|
||||||
|
})
|
||||||
|
lightTheme['@primary-color'] = primary
|
||||||
|
return lightTheme
|
||||||
|
}
|
||||||
|
|
||||||
|
let Dark = (primary) => {
|
||||||
|
Object.keys(dark).forEach((key) => {
|
||||||
|
darkTheme[`${key}`] = dark[key]
|
||||||
|
})
|
||||||
|
darkTheme['@primary-color'] = primary
|
||||||
|
return darkTheme
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
Light,
|
||||||
|
Dark
|
||||||
|
}
|
@ -0,0 +1,428 @@
|
|||||||
|
/* eslint-disable quotes */
|
||||||
|
let lightTheme = {
|
||||||
|
'@ant-prefix': "ant",
|
||||||
|
'@iconfont-css-prefix': "anticon",
|
||||||
|
'@primary-color': "@blue-6",
|
||||||
|
'@success-color': "@green-6",
|
||||||
|
'@info-color': "@blue-6",
|
||||||
|
'@warning-color': "@gold-6",
|
||||||
|
'@error-color': "@red-5",
|
||||||
|
'@highlight-color': "@red-5",
|
||||||
|
'@processing-color': "@blue-6",
|
||||||
|
'@body-background': "#fff",
|
||||||
|
'@component-background': "#fff",
|
||||||
|
'@icon-color': "inherit",
|
||||||
|
'@icon-color-hover': "fade(@black, 75%)",
|
||||||
|
'@heading-color': "fade(#000, 85%)",
|
||||||
|
|
||||||
|
'@text-color': "fade(@black, 65%)",
|
||||||
|
'@text-color-secondary': "fade(@black, 45%)",
|
||||||
|
'@text-color-inverse': "@white",
|
||||||
|
'@heading-color-dark': "fade(@white, 100%)",
|
||||||
|
'@text-color-dark': "fade(@white, 85%)",
|
||||||
|
'@text-color-secondary-dark': "fade(@white, 65%)",
|
||||||
|
'@text-selection-bg': "@primary-color",
|
||||||
|
|
||||||
|
'@border-color-base': "hsv(0, 0, 85%) ",
|
||||||
|
'@border-color-split': "hsv(0, 0, 94%) ",
|
||||||
|
'@border-color-inverse': "@white",
|
||||||
|
'@border-width-base': "1px",
|
||||||
|
'@border-style-base': "solid ",
|
||||||
|
//
|
||||||
|
'@layout-body-background': "#f0f2f5",
|
||||||
|
'@layout-header-background': "#FFF",
|
||||||
|
'@layout-footer-background': "@layout-body-background",
|
||||||
|
'@layout-header-height': "64px",
|
||||||
|
'@layout-header-padding': "0 50px",
|
||||||
|
'@layout-footer-padding': "24px 50px",
|
||||||
|
'@layout-sider-background': "@layout-header-background",
|
||||||
|
'@layout-trigger-height': "48px",
|
||||||
|
'@layout-trigger-background': "#002140",
|
||||||
|
'@layout-trigger-color': "#fff",
|
||||||
|
'@layout-zero-trigger-width': "36px",
|
||||||
|
'@layout-zero-trigger-height': "42px",
|
||||||
|
'@layout-sider-background-light': "#fff",
|
||||||
|
'@layout-trigger-background-light': "#fff",
|
||||||
|
'@layout-trigger-color-light': "@text-color",
|
||||||
|
|
||||||
|
'@font-family': "-apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB',",
|
||||||
|
'@code-family': "'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace",
|
||||||
|
'@font-variant-base': "tabular-nums",
|
||||||
|
'@font-feature-settings-base': "'tnum'",
|
||||||
|
'@font-size-base': "14px",
|
||||||
|
'@font-size-sm': "12px",
|
||||||
|
'@line-height-base': "1.5",
|
||||||
|
'@border-radius-base': "2px",
|
||||||
|
'@border-radius-sm': "2px",
|
||||||
|
'@padding-lg': "24px",
|
||||||
|
'@padding-md': "16px",
|
||||||
|
'@padding-sm': "12px",
|
||||||
|
'@padding-xs': "8px",
|
||||||
|
|
||||||
|
'@disabled-color': "fade(#000, 25%)",
|
||||||
|
'@disabled-bg': "@background-color-base",
|
||||||
|
'@disabled-color-dark': "fade(#fff, 35%)",
|
||||||
|
|
||||||
|
'@link-color': "@primary-color",
|
||||||
|
'@link-decoration': "none",
|
||||||
|
'@link-hover-decoration': "none",
|
||||||
|
|
||||||
|
'@outline-blur-size': "0px",
|
||||||
|
'@outline-width': "2px",
|
||||||
|
'@outline-color': "@primary-color",
|
||||||
|
'@background-color-light': "hsv(0, 0, 98%) ",
|
||||||
|
'@background-color-base': "hsv(0, 0, 96%) ",
|
||||||
|
'@item-active-bg': "@primary-1",
|
||||||
|
'@item-hover-bg': "#f5f5f5",
|
||||||
|
|
||||||
|
'@shadow-color': "rgba(0, 0, 0, 0.15)",
|
||||||
|
'@shadow-color-inverse': "@component-background",
|
||||||
|
'@box-shadow-base': "@shadow-2",
|
||||||
|
'@shadow-1-up': "0 -6px 16px -8px rgba(0, 0, 0, 0.08), 0 -9px 28px 0 rgba(0, 0, 0, 0.05),",
|
||||||
|
'@shadow-1-down': "0 6px 16px -8px rgba(0, 0, 0, 0.08), 0 9px 28px 0 rgba(0, 0, 0, 0.05),",
|
||||||
|
'@shadow-1-left': "-6px 0 16px -8px rgba(0, 0, 0, 0.08), -9px 0 28px 0 rgba(0, 0, 0, 0.05),",
|
||||||
|
'@shadow-1-right': "6px 0 16px -8px rgba(0, 0, 0, 0.08), 9px 0 28px 0 rgba(0, 0, 0, 0.05),",
|
||||||
|
'@shadow-2': "0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 6px 16px 0 rgba(0, 0, 0, 0.08),",
|
||||||
|
'@btn-font-weight': "400",
|
||||||
|
'@btn-border-radius-base': "@border-radius-base",
|
||||||
|
'@btn-border-radius-sm': "@border-radius-base",
|
||||||
|
'@btn-border-width': "@border-width-base",
|
||||||
|
'@btn-border-style': "@border-style-base",
|
||||||
|
'@btn-shadow': "0 2px 0 rgba(0, 0, 0, 0.015)",
|
||||||
|
'@btn-primary-shadow': "0 2px 0 rgba(0, 0, 0, 0.045)",
|
||||||
|
'@btn-text-shadow': "0 -1px 0 rgba(0, 0, 0, 0.12)",
|
||||||
|
'@btn-primary-color': "#fff",
|
||||||
|
'@btn-primary-bg': "@primary-color",
|
||||||
|
'@btn-default-color': "@text-color",
|
||||||
|
'@btn-default-bg': "@component-background",
|
||||||
|
'@btn-default-border': "@border-color-base",
|
||||||
|
'@btn-danger-color': "#fff",
|
||||||
|
'@btn-danger-bg': "@error-color",
|
||||||
|
'@btn-danger-border': "@error-color",
|
||||||
|
'@btn-disable-color': "@disabled-color",
|
||||||
|
'@btn-disable-bg': "@disabled-bg",
|
||||||
|
'@btn-disable-border': "@border-color-base",
|
||||||
|
'@btn-padding-base': "0 @padding-md - 1px",
|
||||||
|
'@btn-font-size-lg': "@font-size-lg",
|
||||||
|
'@btn-font-size-sm': "@font-size-base",
|
||||||
|
'@btn-padding-lg': "@btn-padding-base",
|
||||||
|
'@btn-padding-sm': "0 @padding-xs - 1px",
|
||||||
|
'@btn-height-base': "32px",
|
||||||
|
'@btn-height-lg': "40px",
|
||||||
|
'@btn-height-sm': "24px",
|
||||||
|
'@btn-circle-size': "@btn-height-base",
|
||||||
|
'@btn-circle-size-lg': "@btn-height-lg",
|
||||||
|
'@btn-circle-size-sm': "@btn-height-sm",
|
||||||
|
'@btn-group-border': "@primary-5",
|
||||||
|
|
||||||
|
'@checkbox-size': "16px",
|
||||||
|
'@checkbox-color': "@primary-color",
|
||||||
|
'@checkbox-check-color': "#fff",
|
||||||
|
'@checkbox-border-width': "@border-width-base",
|
||||||
|
|
||||||
|
'@dropdown-selected-color': "@primary-color",
|
||||||
|
'@dropdown-vertical-padding': "5px",
|
||||||
|
'@dropdown-line-height': "22px",
|
||||||
|
'@dropdown-font-size': "@font-size-base",
|
||||||
|
'@empty-font-size': "@font-size-base",
|
||||||
|
|
||||||
|
'@radio-size': "16px",
|
||||||
|
'@radio-dot-color': "@primary-color",
|
||||||
|
'@radio-button-bg': "@btn-default-bg",
|
||||||
|
'@radio-button-checked-bg': "@btn-default-bg",
|
||||||
|
'@radio-button-color': "@btn-default-color",
|
||||||
|
'@radio-button-hover-color': "@primary-5",
|
||||||
|
'@radio-button-active-color': "@primary-7",
|
||||||
|
|
||||||
|
'@screen-xs': "480px",
|
||||||
|
'@screen-xs-min': "@screen-xs",
|
||||||
|
'@screen-sm': "576px",
|
||||||
|
'@screen-sm-min': "@screen-sm",
|
||||||
|
'@screen-md': "768px",
|
||||||
|
'@screen-md-min': "@screen-md",
|
||||||
|
'@screen-lg': "992px",
|
||||||
|
'@screen-lg-min': "@screen-lg",
|
||||||
|
'@screen-xl': "1200px",
|
||||||
|
'@screen-xl-min': "@screen-xl",
|
||||||
|
'@screen-xxl': "1600px",
|
||||||
|
'@screen-xxl-min': "@screen-xxl",
|
||||||
|
|
||||||
|
'@grid-columns': "24",
|
||||||
|
'@grid-gutter-width': "0",
|
||||||
|
|
||||||
|
'@zindex-table-fixed': "auto",
|
||||||
|
'@zindex-affix': "10",
|
||||||
|
'@zindex-back-top': "10",
|
||||||
|
'@zindex-badge': "10",
|
||||||
|
'@zindex-picker-panel': "10",
|
||||||
|
'@zindex-popup-close': "10",
|
||||||
|
'@zindex-modal': "1000",
|
||||||
|
'@zindex-modal-mask': "1000",
|
||||||
|
'@zindex-message': "1010",
|
||||||
|
'@zindex-notification': "1010",
|
||||||
|
'@zindex-popover': "1030",
|
||||||
|
'@zindex-dropdown': "1050",
|
||||||
|
'@zindex-picker': "1050",
|
||||||
|
'@zindex-tooltip': "1060",
|
||||||
|
|
||||||
|
'@animation-duration-slow': "0.3s",
|
||||||
|
'@animation-duration-base': "0.2s",
|
||||||
|
'@animation-duration-fast': "0.1s",
|
||||||
|
|
||||||
|
'@collapse-panel-border-radius': "@border-radius-base",
|
||||||
|
|
||||||
|
'@label-required-color': "@highlight-color",
|
||||||
|
'@label-color': "@heading-color",
|
||||||
|
|
||||||
|
'@form-warning-input-bg': "@input-bg",
|
||||||
|
'@form-item-margin-bottom': "24px",
|
||||||
|
'@form-item-trailing-colon': "true",
|
||||||
|
'@form-vertical-label-padding': "0 0 8px",
|
||||||
|
'@form-vertical-label-margin': "0",
|
||||||
|
'@form-error-input-bg': "@input-bg",
|
||||||
|
|
||||||
|
'@input-height-base': "32px",
|
||||||
|
'@input-height-lg': "40px",
|
||||||
|
'@input-height-sm': "24px",
|
||||||
|
'@input-padding-vertical-base': "4px",
|
||||||
|
'@input-padding-vertical-sm': "1px",
|
||||||
|
'@input-padding-vertical-lg': "6px",
|
||||||
|
'@input-placeholder-color': "hsv(0, 0, 75%)",
|
||||||
|
'@input-color': "@text-color",
|
||||||
|
'@input-border-color': "@border-color-base",
|
||||||
|
'@input-bg': "@component-background",
|
||||||
|
'@input-number-handler-active-bg': "#f4f4f4",
|
||||||
|
'@input-addon-bg': "@background-color-light",
|
||||||
|
'@input-hover-border-color': "@primary-5",
|
||||||
|
'@input-disabled-bg': "@disabled-bg",
|
||||||
|
'@input-outline-offset': "0 0",
|
||||||
|
|
||||||
|
'@select-border-color': "@border-color-base",
|
||||||
|
'@select-item-selected-font-weight': "600px",
|
||||||
|
|
||||||
|
'@tooltip-max-width': "250px",
|
||||||
|
'@tooltip-color': "#fff",
|
||||||
|
'@tooltip-bg': "rgba(0, 0, 0, 0.75)",
|
||||||
|
'@tooltip-arrow-width': "5px",
|
||||||
|
'@tooltip-distance': "@tooltip-arrow-width - 1px + 4px",
|
||||||
|
'@tooltip-arrow-color': "@tooltip-bg",
|
||||||
|
|
||||||
|
'@popover-bg': "@component-background",
|
||||||
|
'@popover-color': "@text-color",
|
||||||
|
'@popover-min-width': "177px",
|
||||||
|
'@popover-arrow-width': "6px",
|
||||||
|
'@popover-arrow-color': "@popover-bg",
|
||||||
|
'@popover-arrow-outer-color': "@popover-bg",
|
||||||
|
'@popover-distance': "@popover-arrow-width + 4px",
|
||||||
|
|
||||||
|
'@modal-body-padding': "24px",
|
||||||
|
'@modal-header-bg': "@component-background",
|
||||||
|
'@modal-footer-bg': "transparent",
|
||||||
|
'@modal-mask-bg': "fade(@black, 45%)",
|
||||||
|
|
||||||
|
'@progress-default-color': "@processing-color",
|
||||||
|
'@progress-remaining-color': "@background-color-base",
|
||||||
|
'@progress-text-color': "@text-color",
|
||||||
|
'@progress-radius': "100px",
|
||||||
|
|
||||||
|
'@menu-inline-toplevel-item-height': "40px",
|
||||||
|
'@menu-item-height': "40px",
|
||||||
|
'@menu-collapsed-width': "80px",
|
||||||
|
'@menu-bg': "@component-background",
|
||||||
|
'@menu-popup-bg': "@component-background",
|
||||||
|
'@menu-item-color': "@text-color",
|
||||||
|
'@menu-highlight-color': "@primary-color",
|
||||||
|
'@menu-item-active-bg': "@primary-1",
|
||||||
|
'@menu-item-active-border-width': "3px",
|
||||||
|
'@menu-item-group-title-color': "@text-color-secondary",
|
||||||
|
'@menu-dark-color': "@text-color-secondary-dark",
|
||||||
|
'@menu-dark-bg': "@layout-header-background",
|
||||||
|
'@menu-dark-arrow-color': "#fff",
|
||||||
|
'@menu-dark-submenu-bg': "#000c17",
|
||||||
|
'@menu-dark-highlight-color': "#fff",
|
||||||
|
'@menu-dark-item-active-bg': "@primary-color",
|
||||||
|
|
||||||
|
'@spin-dot-size-sm': "14px",
|
||||||
|
'@spin-dot-size': "20px",
|
||||||
|
'@spin-dot-size-lg': "32px",
|
||||||
|
|
||||||
|
'@table-header-bg': "@background-color-light",
|
||||||
|
'@table-header-color': "@heading-color",
|
||||||
|
'@table-header-sort-bg': "@background-color-base",
|
||||||
|
'@table-body-sort-bg': "rgba(0, 0, 0, 0.01)",
|
||||||
|
'@table-row-hover-bg': "@item-hover-bg",
|
||||||
|
'@table-selected-row-color': "inherit",
|
||||||
|
'@table-selected-row-bg': "@primary-1",
|
||||||
|
'@table-body-selected-sort-bg': "@table-selected-row-bg",
|
||||||
|
'@table-selected-row-hover-bg': "@table-selected-row-bg",
|
||||||
|
'@table-expanded-row-bg': "#fbfbfb",
|
||||||
|
'@table-padding-vertical': "16px",
|
||||||
|
'@table-padding-horizontal': "16px",
|
||||||
|
'@table-border-radius-base': "@border-radius-base",
|
||||||
|
|
||||||
|
'@tag-default-bg': "@background-color-light",
|
||||||
|
'@tag-default-color': "@text-color",
|
||||||
|
'@tag-font-size': "@font-size-sm",
|
||||||
|
|
||||||
|
'@time-picker-panel-column-width': "56px",
|
||||||
|
'@time-picker-panel-width': "@time-picker-panel-column-width * 3",
|
||||||
|
'@time-picker-selected-bg': "@item-active-bg",
|
||||||
|
|
||||||
|
'@carousel-dot-width': "16px",
|
||||||
|
'@carousel-dot-height': "3px",
|
||||||
|
'@carousel-dot-active-width': "24px",
|
||||||
|
|
||||||
|
'@badge-color': "@error-color",
|
||||||
|
'@badge-height': "20px",
|
||||||
|
'@badge-dot-size': "6px",
|
||||||
|
'@badge-font-size': "@font-size-sm",
|
||||||
|
'@badge-font-weight': "normal",
|
||||||
|
'@badge-status-size': "6px",
|
||||||
|
'@badge-text-color': "@component-background",
|
||||||
|
|
||||||
|
'@rate-star-color': "@yellow-6",
|
||||||
|
'@rate-star-bg': "@border-color-split",
|
||||||
|
|
||||||
|
'@card-head-color': "@heading-color",
|
||||||
|
'@card-head-background': "transparent",
|
||||||
|
'@card-head-padding': "16px",
|
||||||
|
'@card-inner-head-padding': "12px",
|
||||||
|
'@card-padding-base': "24px",
|
||||||
|
'@card-actions-background': "@background-color-light",
|
||||||
|
'@card-background': "@component-background",
|
||||||
|
'@card-shadow': "0 1px 2px -2px rgba(0, 0, 0, 0.16), 0 3px 6px 0 rgba(0, 0, 0, 0.12),",
|
||||||
|
'@card-radius': "@border-radius-base",
|
||||||
|
|
||||||
|
'@comment-padding-base': "16px 0",
|
||||||
|
'@comment-nest-indent': "44px",
|
||||||
|
'@comment-font-size-base': "@font-size-base",
|
||||||
|
'@comment-font-size-sm': "@font-size-sm",
|
||||||
|
'@comment-author-name-color': "@text-color-secondary",
|
||||||
|
'@comment-author-time-color': "#ccc",
|
||||||
|
'@comment-action-color': "@text-color-secondary",
|
||||||
|
'@comment-action-hover-color': "#595959",
|
||||||
|
|
||||||
|
'@tabs-card-head-background': "@background-color-light",
|
||||||
|
'@tabs-card-height': "40px",
|
||||||
|
'@tabs-card-active-color': "@primary-color",
|
||||||
|
'@tabs-title-font-size': "@font-size-base",
|
||||||
|
'@tabs-title-font-size-lg': "@font-size-lg",
|
||||||
|
'@tabs-title-font-size-sm': "@font-size-base",
|
||||||
|
'@tabs-ink-bar-color': "@primary-color",
|
||||||
|
'@tabs-bar-margin': "0 0 16px 0",
|
||||||
|
'@tabs-horizontal-margin': "0 32px 0 0",
|
||||||
|
'@tabs-horizontal-padding': "12px 16px",
|
||||||
|
'@tabs-horizontal-padding-lgr': "16px",
|
||||||
|
'@tabs-horizontal-padding-sm': "8px 16px",
|
||||||
|
'@tabs-vertical-padding': "8px 24px",
|
||||||
|
'@tabs-vertical-margin': "0 0 16px 0",
|
||||||
|
'@tabs-scrolling-size': "32px",
|
||||||
|
'@tabs-highlight-color': "@primary-color",
|
||||||
|
'@tabs-hover-color': "@primary-5",
|
||||||
|
'@tabs-active-color': "@primary-7",
|
||||||
|
'@tabs-card-gutter': "2px",
|
||||||
|
'@tabs-card-tab-active-border-top': "2px solid transparent",
|
||||||
|
|
||||||
|
'@back-top-color': "#fff",
|
||||||
|
'@back-top-bg': "@text-color-secondary",
|
||||||
|
'@back-top-hover-bg': "@text-color",
|
||||||
|
|
||||||
|
'@avatar-size-base': "32px",
|
||||||
|
'@avatar-size-lg': "40px",
|
||||||
|
'@avatar-size-sm': "24px",
|
||||||
|
'@avatar-font-size-base': "18px",
|
||||||
|
'@avatar-font-size-lg': "24px",
|
||||||
|
'@avatar-font-size-sm': "14px",
|
||||||
|
'@avatar-bg': "#ccc",
|
||||||
|
'@avatar-color': "#fff",
|
||||||
|
'@avatar-border-radius': "@border-radius-base",
|
||||||
|
|
||||||
|
'@switch-height': "22px",
|
||||||
|
'@switch-sm-height': "16px",
|
||||||
|
'@switch-sm-checked-margin-left': "-(@switch-sm-height - 3px)",
|
||||||
|
'@switch-disabled-opacity': "0.4",
|
||||||
|
'@switch-color': "@primary-color",
|
||||||
|
'@switch-shadow-color': "fade(#00230b, 20%)",
|
||||||
|
|
||||||
|
'@pagination-item-size': "32px",
|
||||||
|
'@pagination-item-size-sm': "24px",
|
||||||
|
'@pagination-font-weight-active': "500",
|
||||||
|
'@pagination-font-family': "Arial",
|
||||||
|
'@pagination-item-bg-active': "@component-background",
|
||||||
|
|
||||||
|
'@page-header-padding-horizontal': "24px",
|
||||||
|
'@page-header-padding-vertical': "16px",
|
||||||
|
|
||||||
|
'@breadcrumb-base-color': "@text-color-secondary",
|
||||||
|
'@breadcrumb-last-item-color': "@text-color",
|
||||||
|
'@breadcrumb-font-size': "@font-size-base",
|
||||||
|
'@breadcrumb-icon-font-size': "@font-size-base",
|
||||||
|
'@breadcrumb-link-color': "@text-color-secondary",
|
||||||
|
'@breadcrumb-link-color-hover': "@primary-5",
|
||||||
|
'@breadcrumb-separator-color': "@text-color-secondary",
|
||||||
|
'@breadcrumb-separator-margin': "0 @padding-xs",
|
||||||
|
|
||||||
|
'@slider-handle-border-width': "2px",
|
||||||
|
'@slider-handle-shadow': "0",
|
||||||
|
'@slider-margin': "14px 6px 10px",
|
||||||
|
'@slider-rail-background-color': "@background-color-base",
|
||||||
|
'@slider-rail-background-color-hover': "#e1e1e1",
|
||||||
|
'@slider-track-background-color': "@primary-3",
|
||||||
|
'@slider-track-background-color-hover': "@primary-4",
|
||||||
|
'@slider-handle-color': "@primary-3",
|
||||||
|
'@slider-handle-color-hover': "@primary-4",
|
||||||
|
'@slider-handle-color-focus': "tint(@primary-color, 20%)",
|
||||||
|
'@slider-handle-color-focus-shadow': "fade(@primary-color, 20%)",
|
||||||
|
'@slider-handle-color-tooltip-open': "@primary-color",
|
||||||
|
'@slider-dot-border-color': "@border-color-split",
|
||||||
|
'@slider-dot-border-color-active': "tint(@primary-color, 50%)",
|
||||||
|
'@slider-disabled-color': "@disabled-color",
|
||||||
|
'@slider-disabled-background-color': "@component-background",
|
||||||
|
|
||||||
|
'@tree-title-height': "24px",
|
||||||
|
'@tree-child-padding': "18px",
|
||||||
|
'@tree-directory-selected-color': "#fff",
|
||||||
|
'@tree-directory-selected-bg': "@primary-color",
|
||||||
|
|
||||||
|
'@collapse-header-padding': "12px 16px",
|
||||||
|
'@collapse-header-padding-extra': "40px",
|
||||||
|
'@collapse-header-bg': "@background-color-light",
|
||||||
|
'@collapse-content-padding': "@padding-md",
|
||||||
|
'@collapse-content-bg': "@component-background",
|
||||||
|
'@skeleton-color': "#f2f2f2",
|
||||||
|
'@transfer-header-height': "40px",
|
||||||
|
'@transfer-disabled-bg': "@disabled-bg",
|
||||||
|
'@transfer-list-height': "200px",
|
||||||
|
'@message-notice-content-padding': "10px 16px",
|
||||||
|
'@wave-animation-width': "6px",
|
||||||
|
|
||||||
|
'@alert-success-border-color': "~`colorPalette('@{success-color}', 3) `",
|
||||||
|
'@alert-success-bg-color': "~`colorPalette('@{success-color}', 1) `",
|
||||||
|
'@alert-success-icon-color': "@success-color",
|
||||||
|
'@alert-info-border-color': "~`colorPalette('@{info-color}', 3) `",
|
||||||
|
'@alert-info-bg-color': "~`colorPalette('@{info-color}', 1) `",
|
||||||
|
'@alert-info-icon-color': "@info-color",
|
||||||
|
'@alert-warning-border-color': "~`colorPalette('@{warning-color}', 3) `",
|
||||||
|
'@alert-warning-bg-color': "~`colorPalette('@{warning-color}', 1) `",
|
||||||
|
'@alert-warning-icon-color': "@warning-color",
|
||||||
|
'@alert-error-border-color': "~`colorPalette('@{error-color}', 3) `",
|
||||||
|
'@alert-error-bg-color': "~`colorPalette('@{error-color}', 1) `",
|
||||||
|
'@alert-error-icon-color': "@error-color",
|
||||||
|
|
||||||
|
'@list-header-background': "transparent",
|
||||||
|
'@list-footer-background': "transparent",
|
||||||
|
'@list-empty-text-padding': "@padding-md",
|
||||||
|
'@list-item-padding': "@padding-sm 0",
|
||||||
|
'@list-item-meta-margin-bottom': "@padding-md",
|
||||||
|
'@list-item-meta-avatar-margin-right': "@padding-md",
|
||||||
|
'@list-item-meta-title-margin-bottom': "@padding-sm",
|
||||||
|
'@statistic-title-font-size': "@font-size-base",
|
||||||
|
|
||||||
|
'@statistic-content-font-size': "24px",
|
||||||
|
'@statistic-unit-font-size': "16px",
|
||||||
|
'@statistic-font-family': "@font-family",
|
||||||
|
|
||||||
|
'@drawer-header-padding': "16px 24px",
|
||||||
|
'@drawer-body-padding': "24px"
|
||||||
|
}
|
||||||
|
export default lightTheme
|
@ -0,0 +1,38 @@
|
|||||||
|
module.exports = [
|
||||||
|
'@primary-color',
|
||||||
|
'@layout-header-background',
|
||||||
|
'@layout-sider-background',
|
||||||
|
'@layout-body-background',
|
||||||
|
'@background-color-base',
|
||||||
|
'@body-background',
|
||||||
|
'@layout-sider-background',
|
||||||
|
'@component-background',
|
||||||
|
'@layout-header-background',
|
||||||
|
'@input-bg',
|
||||||
|
'@btn-default-bg',
|
||||||
|
'@border-color-base',
|
||||||
|
'@border-color-split',
|
||||||
|
'@heading-color',
|
||||||
|
'@text-color',
|
||||||
|
'@text-color-secondary',
|
||||||
|
'@table-selected-row-bg',
|
||||||
|
'@table-expanded-row-bg',
|
||||||
|
'@table-header-bg',
|
||||||
|
'@table-row-hover-bg',
|
||||||
|
'@layout-trigger-color',
|
||||||
|
'@layout-trigger-background',
|
||||||
|
'@alert-message-color',
|
||||||
|
'@item-hover-bg',
|
||||||
|
'@item-active-bg',
|
||||||
|
'@disabled-color',
|
||||||
|
'@tag-default-bg',
|
||||||
|
'@popover-bg',
|
||||||
|
'@wait-icon-color',
|
||||||
|
'@background-color-light',
|
||||||
|
'@collapse-header-bg',
|
||||||
|
'@info-color',
|
||||||
|
'@primary-color',
|
||||||
|
'@highlight-color',
|
||||||
|
'@warning-color',
|
||||||
|
'@menu-dark-submenu-bg'
|
||||||
|
]
|
@ -0,0 +1,17 @@
|
|||||||
|
@import "~antd/lib/style/themes/default.less";
|
||||||
|
|
||||||
|
@primary-color: #2196f3; // 全局主色
|
||||||
|
// @link-color: #1890ff; // 链接色
|
||||||
|
// @success-color: #52c41a; // 成功色
|
||||||
|
// @warning-color: #faad14; // 警告色
|
||||||
|
// @error-color: #f5222d; // 错误色
|
||||||
|
// @font-size-base: 14px; // 主字号
|
||||||
|
// @heading-color: rgba(0, 0, 0, 0.85); // 标题色
|
||||||
|
// @text-color: rgba(0, 0, 0, 0.65); // 主文本色
|
||||||
|
// @text-color-secondary : rgba(0, 0, 0, .45); // 次文本色
|
||||||
|
// @disabled-color : rgba(0, 0, 0, .25); // 失效色
|
||||||
|
// @border-radius-base: 4px; // 组件/浮层圆角
|
||||||
|
// @border-color-base: #d9d9d9; // 边框色
|
||||||
|
// @box-shadow-base: 0 2px 8px rgba(0, 0, 0, 0.15); // 浮层阴影
|
||||||
|
@layout-header-background: #FFF;
|
||||||
|
@layout-sider-background: #FFF;
|
@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es6",
|
||||||
|
"lib": [
|
||||||
|
"dom",
|
||||||
|
"dom.iterable",
|
||||||
|
"esnext"
|
||||||
|
],
|
||||||
|
"allowJs": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"strict": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"noEmit": true,
|
||||||
|
"jsx": "react",
|
||||||
|
|
||||||
|
"experimentalDecorators": true
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src",
|
||||||
|
"typings/externals.d.ts"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
|||||||
|
declare module '*.less'
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,14 @@
|
|||||||
|
.DS_Store
|
||||||
|
node_modules/
|
||||||
|
/dist/
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.idea
|
||||||
|
.vscode
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
@ -0,0 +1,21 @@
|
|||||||
|
# vue-starter
|
||||||
|
|
||||||
|
> A vuejs starter project integrated with vuex, vue-router, less, iview
|
||||||
|
|
||||||
|
## Build Setup
|
||||||
|
|
||||||
|
``` bash
|
||||||
|
# install dependencies
|
||||||
|
npm install
|
||||||
|
|
||||||
|
# serve with hot reload at localhost:8080
|
||||||
|
npm run dev
|
||||||
|
|
||||||
|
# build for production with minification
|
||||||
|
npm run build
|
||||||
|
|
||||||
|
# build for production and view the bundle analyzer report
|
||||||
|
npm run build --report
|
||||||
|
```
|
||||||
|
|
||||||
|
For a detailed explanation on how things work, check out the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader).
|
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 6.7 KiB |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue