feat: react-pc
This commit is contained in:
parent
671157aee5
commit
cd2e8824e0
16
.editorconfig
Executable file
16
.editorconfig
Executable file
@ -0,0 +1,16 @@
|
|||||||
|
# http://editorconfig.org
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
end_of_line = lf
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
trim_trailing_whitespace = false
|
||||||
|
|
||||||
|
[Makefile]
|
||||||
|
indent_style = tab
|
4
.eslintrc.js
Executable file
4
.eslintrc.js
Executable file
@ -0,0 +1,4 @@
|
|||||||
|
module.exports = {
|
||||||
|
extends: [require.resolve('uniubi-lint/typescript/react')],
|
||||||
|
rules: {},
|
||||||
|
};
|
23
.gitignore
vendored
Executable file
23
.gitignore
vendored
Executable file
@ -0,0 +1,23 @@
|
|||||||
|
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||||
|
|
||||||
|
# dependencies
|
||||||
|
/node_modules
|
||||||
|
/npm-debug.log*
|
||||||
|
/yarn-error.log
|
||||||
|
/yarn.lock
|
||||||
|
/package-lock.json
|
||||||
|
|
||||||
|
# production
|
||||||
|
/dist
|
||||||
|
|
||||||
|
# misc
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# umi
|
||||||
|
/src/.umi
|
||||||
|
/src/.umi-production
|
||||||
|
/src/.umi-test
|
||||||
|
/.env.local
|
||||||
|
|
||||||
|
# editor directories and files
|
||||||
|
.idea
|
8
.prettierignore
Normal file
8
.prettierignore
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
**/*.md
|
||||||
|
**/*.svg
|
||||||
|
**/*.ejs
|
||||||
|
**/*.html
|
||||||
|
package.json
|
||||||
|
.umi
|
||||||
|
.umi-production
|
||||||
|
.umi-test
|
7
.umirc.pre.ts
Normal file
7
.umirc.pre.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { defineConfig } from 'umi';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
define: {
|
||||||
|
'process.env.BASE_API': '/api',
|
||||||
|
},
|
||||||
|
});
|
10
.umirc.production.ts
Normal file
10
.umirc.production.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import { defineConfig } from 'umi';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
define: {
|
||||||
|
'process.env.BASE_API': '/api',
|
||||||
|
},
|
||||||
|
extraBabelPlugins: [
|
||||||
|
['transform-remove-console', { "exclude": [ "error", "warn"] }]
|
||||||
|
],
|
||||||
|
});
|
7
.umirc.release.ts
Normal file
7
.umirc.release.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { defineConfig } from 'umi';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
define: {
|
||||||
|
'process.env.BASE_API': '/api',
|
||||||
|
},
|
||||||
|
});
|
7
.umirc.test.ts
Normal file
7
.umirc.test.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { defineConfig } from 'umi';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
define: {
|
||||||
|
'process.env.BASE_API': '/api',
|
||||||
|
},
|
||||||
|
});
|
107
.umirc.ts
Normal file
107
.umirc.ts
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
import { defineConfig } from 'umi';
|
||||||
|
import Icon from './public/favicon.ico'
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
favicon: Icon,
|
||||||
|
hash: true,
|
||||||
|
dva: {
|
||||||
|
immer: true,
|
||||||
|
hmr: false,
|
||||||
|
},
|
||||||
|
webpack5: {},
|
||||||
|
dynamicImport: {
|
||||||
|
loading: '@/components/PageLoading/index',
|
||||||
|
},
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
path: '/window',
|
||||||
|
component: '@/layouts/WindowLayout',
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
path: 'demo',
|
||||||
|
component: '@/pages/index',
|
||||||
|
name: '一级菜单',
|
||||||
|
title: '一级菜单',
|
||||||
|
icon: 'EntranceOutlined',
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/',
|
||||||
|
component: '@/layouts/BasicLayout',
|
||||||
|
// wrappers: ['@/wrappers/SecurityLayout'],
|
||||||
|
routes: [
|
||||||
|
{ exact: true, path: '/', redirect: '/a' },
|
||||||
|
{
|
||||||
|
path: 'a',
|
||||||
|
component: '@/pages/index',
|
||||||
|
name: '一级菜单',
|
||||||
|
title: '一级菜单',
|
||||||
|
icon: 'EntranceOutlined',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'b',
|
||||||
|
name: '一级菜单',
|
||||||
|
title: '一级菜单',
|
||||||
|
icon: 'EntranceOutlined',
|
||||||
|
routes: [
|
||||||
|
{ exact: true, path: '/b', redirect: '/b/c' },
|
||||||
|
{
|
||||||
|
path: 'c',
|
||||||
|
component: '@/pages/index',
|
||||||
|
name: '二级菜单',
|
||||||
|
title: '二级菜单',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
define: {
|
||||||
|
'process.env.BASE_API': '/api',
|
||||||
|
},
|
||||||
|
proxy: {
|
||||||
|
'/api': {
|
||||||
|
target: 'http://mock.com',
|
||||||
|
changeOrigin: true,
|
||||||
|
pathRewrite: { '^/api': '' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
theme: {
|
||||||
|
// 'primary-color': '#2228e0',
|
||||||
|
// 'info-color': '#2228e0',
|
||||||
|
// 'processing-color': '#2228e0',
|
||||||
|
// 'link-color': '#2228e0',
|
||||||
|
// 'success-color': '#46cf84',
|
||||||
|
// 'warning-color': '#ffa42e',
|
||||||
|
// 'error-color': '#fa4646',
|
||||||
|
// 'highlight-color': '#fa4646',
|
||||||
|
// 'normal-color': '#e0e0e0',
|
||||||
|
// 'heading-color': '#000000',
|
||||||
|
// 'text-color': '#4a4a4a',
|
||||||
|
// 'text-color-secondary': '#7c7c7c',
|
||||||
|
// 'disabled-color': '#c7c7c7',
|
||||||
|
// 'border-radius-base': '3px',
|
||||||
|
// 'border-color-base': '#e0e0e0',
|
||||||
|
// 'font-family':
|
||||||
|
// '"Alibaba PuHuiTi", "SourceHanSans TW", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"',
|
||||||
|
// 'padding-lg': '24px',
|
||||||
|
// 'padding-md': '16px',
|
||||||
|
// 'padding-sm': '12px',
|
||||||
|
// 'padding-xs': '8px',
|
||||||
|
// 'padding-xxs': '4px',
|
||||||
|
// 'margin-lg': '24px',
|
||||||
|
// 'margin-md': '16px',
|
||||||
|
// 'margin-sm': '12px',
|
||||||
|
// 'margin-xs': '8px',
|
||||||
|
// 'margin-xxs': '4px',
|
||||||
|
},
|
||||||
|
locale: {
|
||||||
|
default: 'zh-CN',
|
||||||
|
antd: true,
|
||||||
|
},
|
||||||
|
ignoreMomentLocale: true,
|
||||||
|
targets: {
|
||||||
|
ie: 10,
|
||||||
|
}
|
||||||
|
});
|
40
.vscode/settings.json
vendored
Normal file
40
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
{
|
||||||
|
"editor.codeActionsOnSave": {
|
||||||
|
"source.fixAll.eslint": true
|
||||||
|
},
|
||||||
|
"eslint.validate": [
|
||||||
|
"javascript",
|
||||||
|
"react",
|
||||||
|
"typescript",
|
||||||
|
"typescriptreact",
|
||||||
|
"vue"
|
||||||
|
],
|
||||||
|
"editor.formatOnSave": true,
|
||||||
|
"[typescriptreact]": {
|
||||||
|
"editor.defaultFormatter": null
|
||||||
|
},
|
||||||
|
"[javascript]": {
|
||||||
|
"editor.defaultFormatter": null
|
||||||
|
},
|
||||||
|
"[typescript]": {
|
||||||
|
"editor.defaultFormatter": null
|
||||||
|
},
|
||||||
|
"[javascriptreact]": {
|
||||||
|
"editor.defaultFormatter": null
|
||||||
|
},
|
||||||
|
"[json]": {
|
||||||
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
|
},
|
||||||
|
"[less]": {
|
||||||
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
|
},
|
||||||
|
"[scss]": {
|
||||||
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
|
},
|
||||||
|
"[css]": {
|
||||||
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
|
},
|
||||||
|
"[jsonc]": {
|
||||||
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
|
}
|
||||||
|
}
|
0
CHANGELOG.md
Normal file
0
CHANGELOG.md
Normal file
35
README.md
35
README.md
@ -1,34 +1 @@
|
|||||||
## 目前已有脚手架列表
|
# react-template
|
||||||
|
|
||||||
| 名称 | 说明 | 技术栈 |
|
|
||||||
| ------- | --------------------------- | --------------------- |
|
|
||||||
| nextJs | 基于 React 的服务端渲染方案 | nextJs + axios + antd |
|
|
||||||
| ReactJs | 基于 React 的业务型脚手架 | umiJs + axios + antd |
|
|
||||||
| TaroJs | 基于 React 的多端适配方案 | TaroJs 全家桶 |
|
|
||||||
| Vue | 基于 Vue 的业务型脚手架 | vueJs 全家桶 |
|
|
||||||
| Gulp | 基于 Gulp 的清凉型脚手架 | -- |
|
|
||||||
|
|
||||||
## 快速上手
|
|
||||||
|
|
||||||
### 1. 安装相关依赖
|
|
||||||
|
|
||||||
```js
|
|
||||||
// 推荐
|
|
||||||
yarn global add @nicecode/cli
|
|
||||||
|
|
||||||
// or
|
|
||||||
// npm install @nicecode/cli -g
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. 运行命令
|
|
||||||
|
|
||||||
```js
|
|
||||||
// 查看脚手架版本号,是否安装成功
|
|
||||||
nice - V
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. 创建项目
|
|
||||||
|
|
||||||
```js
|
|
||||||
nice create ${项目名称}
|
|
||||||
```
|
|
0
mock/.gitkeep
Normal file
0
mock/.gitkeep
Normal file
55
package.json
Normal file
55
package.json
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
{
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"start": "umi dev",
|
||||||
|
"build": "umi build",
|
||||||
|
"build:test": "cross-env UMI_ENV=test umi build",
|
||||||
|
"build:release": "cross-env UMI_ENV=release umi build",
|
||||||
|
"build:pre": "cross-env UMI_ENV=pre umi build",
|
||||||
|
"build:production": "cross-env UMI_ENV=production umi build",
|
||||||
|
"lint": "eslint 'src/**/*.{js,jsx,tsx,ts}'",
|
||||||
|
"lint:fix": "eslint 'src/**/*.{js,jsx,tsx,ts}' --fix",
|
||||||
|
"prettier": "prettier --write '**/*.{less,css,md,json}'",
|
||||||
|
"test": "umi-test",
|
||||||
|
"test:coverage": "umi-test --coverage"
|
||||||
|
},
|
||||||
|
"gitHooks": {
|
||||||
|
"pre-commit": "tsc --noEmit && lint-staged"
|
||||||
|
},
|
||||||
|
"lint-staged": {
|
||||||
|
"*.{js,jsx,ts,tsx}": [
|
||||||
|
"npm run lint:fix",
|
||||||
|
"git add ."
|
||||||
|
],
|
||||||
|
"*.{less,css,md,json}": [
|
||||||
|
"npm run prettier",
|
||||||
|
"git add ."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@ant-design/pro-layout": "^6.15.4",
|
||||||
|
"@materials/user-avatar": "^1.0.1",
|
||||||
|
"@ant-design/icons-react": "^2.0.10",
|
||||||
|
"antd": "^100.0.1",
|
||||||
|
"axios": "^0.19.2",
|
||||||
|
"classnames": "^2.2.6",
|
||||||
|
"js-cookie": "^2.2.1",
|
||||||
|
"poseidon-web-monitoring": "^1.1.3",
|
||||||
|
"react": "^17.0.1",
|
||||||
|
"react-dom": "^17.0.1",
|
||||||
|
"umi": "^3.5.15"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/classnames": "^2.2.10",
|
||||||
|
"@umijs/preset-react": "1.x",
|
||||||
|
"@umijs/test": "^3.0.16",
|
||||||
|
"babel-plugin-transform-remove-console": "^6.9.4",
|
||||||
|
"cross-env": "^7.0.2",
|
||||||
|
"end-type-to-front-type": "^1.2.1",
|
||||||
|
"eslint": "^7.16.0",
|
||||||
|
"lint-staged": "^10.0.7",
|
||||||
|
"prettier": "^1.19.1",
|
||||||
|
"typescript": "^4.1.3",
|
||||||
|
"yorkie": "^2.0.0"
|
||||||
|
}
|
||||||
|
}
|
BIN
public/favicon.ico
Normal file
BIN
public/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 66 KiB |
5
src/app.ts
Normal file
5
src/app.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import { enableES5 } from 'immer';
|
||||||
|
import '@/styles/index.less';
|
||||||
|
import '@/styles/reset.less';
|
||||||
|
|
||||||
|
enableES5();
|
2
src/assets/data/code.ts
Normal file
2
src/assets/data/code.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
// 业务错误码
|
||||||
|
export default {};
|
5
src/assets/data/constants.ts
Normal file
5
src/assets/data/constants.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export const DATE_FORMAT = 'yyyy-MM-dd';
|
||||||
|
|
||||||
|
export const TIME_FORMAT = 'HH:mm:ss';
|
||||||
|
|
||||||
|
export const DATE_TIME_FORMAT = `${DATE_FORMAT} ${TIME_FORMAT}`;
|
BIN
src/assets/images/logo.png
Normal file
BIN
src/assets/images/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
3
src/components/PageLoading/index.tsx
Normal file
3
src/components/PageLoading/index.tsx
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import { PageLoading } from '@ant-design/pro-layout';
|
||||||
|
|
||||||
|
export default PageLoading;
|
12
src/components/User/index.tsx
Normal file
12
src/components/User/index.tsx
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import UserAvatar from '@materials/user-avatar';
|
||||||
|
|
||||||
|
const User = () => {
|
||||||
|
return (
|
||||||
|
<UserAvatar name="admin">
|
||||||
|
<div>个人中心</div>
|
||||||
|
<div>退出登录</div>
|
||||||
|
</UserAvatar>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default User;
|
26
src/interfaces/base.ts
Normal file
26
src/interfaces/base.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
export interface BaseProps {
|
||||||
|
className?: string;
|
||||||
|
style?: React.CSSProperties;
|
||||||
|
children?: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Pagination {
|
||||||
|
total: number;
|
||||||
|
size: number;
|
||||||
|
index: number;
|
||||||
|
length: number;
|
||||||
|
beginIndex: number;
|
||||||
|
endIndex: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BaseResponse {
|
||||||
|
code: string;
|
||||||
|
msg: string;
|
||||||
|
memo: string;
|
||||||
|
data: any;
|
||||||
|
page?: Pagination;
|
||||||
|
result: number;
|
||||||
|
success: boolean;
|
||||||
|
requestId: string;
|
||||||
|
linkTime: number;
|
||||||
|
}
|
44
src/layouts/BasicLayout/Breadcrumb.tsx
Normal file
44
src/layouts/BasicLayout/Breadcrumb.tsx
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import classnames from 'classnames';
|
||||||
|
import BreadcrumbItem from './BreadcrumbItem';
|
||||||
|
import './index.less';
|
||||||
|
|
||||||
|
interface BreadcrumbProps {
|
||||||
|
routes: any[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const Breadcrumb: React.FC<BreadcrumbProps> = ({ routes }) => {
|
||||||
|
const validRoutes = routes.filter(item => !!item);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="g-basic-layout-header-breadcrumb">
|
||||||
|
<BreadcrumbItem.Root
|
||||||
|
className={classnames({
|
||||||
|
'g-basic-layout-header-breadcrumb-item-active': !validRoutes.length,
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
{validRoutes.map(
|
||||||
|
(item: any, index) =>
|
||||||
|
item && (
|
||||||
|
<span key={item.key}>
|
||||||
|
<span className="g-basic-layout-header-breadcrumb-divider">
|
||||||
|
/
|
||||||
|
</span>
|
||||||
|
<BreadcrumbItem
|
||||||
|
path={item.path}
|
||||||
|
className={classnames({
|
||||||
|
'g-basic-layout-header-breadcrumb-item-active':
|
||||||
|
index === validRoutes.length - 1,
|
||||||
|
})}
|
||||||
|
disabled={index === validRoutes.length - 1}
|
||||||
|
>
|
||||||
|
{item.name}
|
||||||
|
</BreadcrumbItem>
|
||||||
|
</span>
|
||||||
|
),
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Breadcrumb;
|
48
src/layouts/BasicLayout/BreadcrumbItem.tsx
Normal file
48
src/layouts/BasicLayout/BreadcrumbItem.tsx
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { history } from 'umi';
|
||||||
|
import { Button } from 'antd';
|
||||||
|
import { ButtonProps } from 'antd/lib/button';
|
||||||
|
import { HomeFilled } from '@ant-design/icons-react';
|
||||||
|
import classnames from 'classnames';
|
||||||
|
import './index.less';
|
||||||
|
|
||||||
|
interface BreadcrumbItemProps extends ButtonProps {
|
||||||
|
path: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const BreadcrumbItem = ({
|
||||||
|
path,
|
||||||
|
children,
|
||||||
|
className,
|
||||||
|
...rest
|
||||||
|
}: BreadcrumbItemProps): JSX.Element => {
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
className={classnames('g-basic-layout-header-breadcrumb-item', className)}
|
||||||
|
type="text"
|
||||||
|
onClick={() => history.push(path)}
|
||||||
|
{...rest}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const RootItem: React.FC<ButtonProps> = ({ className, ...rest }) => (
|
||||||
|
<Button
|
||||||
|
className={classnames(
|
||||||
|
'g-basic-layout-header-breadcrumb-item',
|
||||||
|
'g-basic-layout-header-breadcrumb-item-root',
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
type="text"
|
||||||
|
onClick={() => history.push('/')}
|
||||||
|
{...rest}
|
||||||
|
>
|
||||||
|
<HomeFilled />
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
|
||||||
|
BreadcrumbItem.Root = RootItem;
|
||||||
|
|
||||||
|
export default BreadcrumbItem;
|
84
src/layouts/BasicLayout/index.less
Normal file
84
src/layouts/BasicLayout/index.less
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
@import "../../styles/var.less";
|
||||||
|
|
||||||
|
.g-basic-layout {
|
||||||
|
&-header {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
&-breadcrumb {
|
||||||
|
.g-basic-layout-header-breadcrumb-item {
|
||||||
|
color: @M4;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
color: @M4;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: @S3;
|
||||||
|
background-color: @M7;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
background-color: @M7;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-active {
|
||||||
|
color: @M2;
|
||||||
|
|
||||||
|
&[disabled],
|
||||||
|
&[disabled]:hover,
|
||||||
|
&[disabled]:focus,
|
||||||
|
&[disabled]:active {
|
||||||
|
color: @M2;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.g-basic-layout-header-breadcrumb-divider {
|
||||||
|
color: @M4;
|
||||||
|
margin: 0 @Sp-3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-pro-sider-logo img {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-pro-global-header {
|
||||||
|
background-color: @M7;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-pro-basicLayout-content {
|
||||||
|
margin: @Sp-5 @Sp-8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-page-header-heading {
|
||||||
|
&-left {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-title {
|
||||||
|
font-size: @Fs-4;
|
||||||
|
line-height: @Lh-4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-layout {
|
||||||
|
background-color: @M7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-layout-sider,
|
||||||
|
.ant-menu.ant-menu-dark,
|
||||||
|
.ant-menu-dark .ant-menu-sub,
|
||||||
|
.ant-menu.ant-menu-dark .ant-menu-sub {
|
||||||
|
background-color: @S1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-layout-content {
|
||||||
|
min-height: calc(100vh - 72px);
|
||||||
|
}
|
||||||
|
}
|
77
src/layouts/BasicLayout/index.tsx
Normal file
77
src/layouts/BasicLayout/index.tsx
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { history, Link } from 'umi';
|
||||||
|
import { EntranceOutlined } from '@ant-design/icons-react';
|
||||||
|
import ProLayout, { MenuDataItem } from '@ant-design/pro-layout';
|
||||||
|
import { HeaderViewProps } from '@ant-design/pro-layout/lib/Header';
|
||||||
|
import User from '@/components/User';
|
||||||
|
import Breadcrumb from './Breadcrumb';
|
||||||
|
import './index.less';
|
||||||
|
|
||||||
|
const BasicLayout: React.FC = ({ children, ...rest }) => {
|
||||||
|
const iconMap = {
|
||||||
|
EntranceOutlined: <EntranceOutlined />,
|
||||||
|
};
|
||||||
|
|
||||||
|
// 带子菜单的一级导航
|
||||||
|
const renderSubMenuItem = (itemProps: MenuDataItem): React.ReactNode => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{itemProps.icon && iconMap[itemProps.icon as string]}
|
||||||
|
<span>{itemProps.name}</span>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 不带子菜单的导航
|
||||||
|
const renderMenuItem = (itemProps: MenuDataItem): React.ReactNode => {
|
||||||
|
return itemProps.isUrl || !itemProps.path ? (
|
||||||
|
<>
|
||||||
|
{itemProps.icon && iconMap[itemProps.icon as string]}
|
||||||
|
<span>{itemProps.name}</span>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<Link to={itemProps.path}>
|
||||||
|
{itemProps.icon && iconMap[itemProps.icon as string]}
|
||||||
|
<span>{itemProps.name}</span>
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 面包屑
|
||||||
|
const renderHeaderContent: (
|
||||||
|
props: HeaderViewProps,
|
||||||
|
) => React.ReactNode = props => {
|
||||||
|
// 匹配到到路由和面包屑信息
|
||||||
|
const { matchMenuKeys, breadcrumb } = props as any;
|
||||||
|
const matchRoutes = matchMenuKeys.map((item: any) => breadcrumb[item]);
|
||||||
|
return (
|
||||||
|
<div className="g-basic-layout-header">
|
||||||
|
<Breadcrumb routes={matchRoutes} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 用户信息
|
||||||
|
const renderUserAvatar = () => <User />;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ProLayout
|
||||||
|
className="g-basic-layout"
|
||||||
|
logo="https://fe-cloud.uni-ubi.com/image/1625038486292-logo-r.png?x-oss-process=img/q/80"
|
||||||
|
title="Uni-Ubi"
|
||||||
|
siderWidth={180}
|
||||||
|
fixedHeader
|
||||||
|
fixSiderbar
|
||||||
|
onMenuHeaderClick={() => history.push('/')}
|
||||||
|
subMenuItemRender={renderSubMenuItem}
|
||||||
|
menuItemRender={renderMenuItem}
|
||||||
|
headerContentRender={renderHeaderContent}
|
||||||
|
rightContentRender={renderUserAvatar}
|
||||||
|
{...rest}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</ProLayout>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default BasicLayout;
|
5
src/layouts/BlankLayout/index.tsx
Normal file
5
src/layouts/BlankLayout/index.tsx
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
const BlankLayout: React.FC = ({ children }) => <>{children}</>;
|
||||||
|
|
||||||
|
export default BlankLayout;
|
33
src/layouts/WindowLayout/Header.tsx
Normal file
33
src/layouts/WindowLayout/Header.tsx
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import { history } from 'umi';
|
||||||
|
import { Image, Divider } from 'antd';
|
||||||
|
import User from '@/components/User';
|
||||||
|
import './index.less';
|
||||||
|
|
||||||
|
const Header = () => {
|
||||||
|
return (
|
||||||
|
<div className="g-window-layout-header">
|
||||||
|
<div
|
||||||
|
className="g-window-layout-header-logo"
|
||||||
|
onClick={() => history.push('/')}
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
src={require('../../assets/images/logo.png')}
|
||||||
|
alt="logo"
|
||||||
|
preview={false}
|
||||||
|
width={36}
|
||||||
|
height={24}
|
||||||
|
/>
|
||||||
|
<Divider
|
||||||
|
type="vertical"
|
||||||
|
className="g-window-layout-header-logo-divider"
|
||||||
|
/>
|
||||||
|
<span className="g-window-layout-header-logo-text">react-template</span>
|
||||||
|
</div>
|
||||||
|
<div className="g-window-layout-header-actions">
|
||||||
|
<User />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Header;
|
65
src/layouts/WindowLayout/index.less
Normal file
65
src/layouts/WindowLayout/index.less
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
@import "../../styles/var.less";
|
||||||
|
|
||||||
|
@headerHeader: 64px;
|
||||||
|
|
||||||
|
.g-window-layout {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-width: 1200px;
|
||||||
|
min-height: 100vh;
|
||||||
|
background-color: @M7;
|
||||||
|
|
||||||
|
&-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
height: @headerHeader;
|
||||||
|
width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
|
||||||
|
&-wrapper {
|
||||||
|
background-color: #000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-logo {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
color: #ffffff;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&-divider.ant-divider {
|
||||||
|
border-color: #ffffff;
|
||||||
|
height: 12px;
|
||||||
|
margin: 0 @Sp-5;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-text {
|
||||||
|
font-size: @Fs-3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-actions {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-content {
|
||||||
|
flex: 1;
|
||||||
|
width: 1200px;
|
||||||
|
min-height: 600px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: @Sp-8;
|
||||||
|
background-color: #ffffff;
|
||||||
|
box-shadow: @Sh-2;
|
||||||
|
border-radius: @Ra-2;
|
||||||
|
|
||||||
|
&-wrapper {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex: 1;
|
||||||
|
min-height: 500px;
|
||||||
|
padding: @Sp-8 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
18
src/layouts/WindowLayout/index.tsx
Normal file
18
src/layouts/WindowLayout/index.tsx
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import Header from './Header';
|
||||||
|
import './index.less';
|
||||||
|
|
||||||
|
const WindowLayout: React.FC = ({ children }) => {
|
||||||
|
return (
|
||||||
|
<div className="g-window-layout">
|
||||||
|
<div className="g-window-layout-header-wrapper">
|
||||||
|
<Header />
|
||||||
|
</div>
|
||||||
|
<div className="g-window-layout-content-wrapper">
|
||||||
|
<div className="g-window-layout-content">{children}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default WindowLayout;
|
1
src/locales/zh-CN.ts
Normal file
1
src/locales/zh-CN.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export default {};
|
5
src/models/connect.ts
Normal file
5
src/models/connect.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import { UserModelState } from './user';
|
||||||
|
|
||||||
|
export interface ConnectState {
|
||||||
|
user: UserModelState;
|
||||||
|
}
|
56
src/models/user.ts
Normal file
56
src/models/user.ts
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
import { ImmerReducer, Effect } from 'umi';
|
||||||
|
import { SubscriptionsMapObject } from 'dva';
|
||||||
|
import { getUserInfo } from '@/services/user';
|
||||||
|
|
||||||
|
export interface UserInfo {
|
||||||
|
name?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UserModelState {
|
||||||
|
info: UserInfo;
|
||||||
|
token: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UserModelType {
|
||||||
|
namespace: 'user';
|
||||||
|
state: UserModelState;
|
||||||
|
effects: {
|
||||||
|
fetchUser: Effect;
|
||||||
|
};
|
||||||
|
reducers: {
|
||||||
|
setUserInfo: ImmerReducer<UserModelState>;
|
||||||
|
setToken: ImmerReducer<UserModelState>;
|
||||||
|
};
|
||||||
|
subscriptions: SubscriptionsMapObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
const UserModel: UserModelType = {
|
||||||
|
namespace: 'user',
|
||||||
|
state: {
|
||||||
|
info: {},
|
||||||
|
token: '',
|
||||||
|
},
|
||||||
|
effects: {
|
||||||
|
// 获取用户信息
|
||||||
|
*fetchUser(_, { call, put }) {
|
||||||
|
const response = yield call(getUserInfo);
|
||||||
|
yield put({
|
||||||
|
type: 'setUserInfo',
|
||||||
|
payload: response,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
reducers: {
|
||||||
|
// 修改用户信息
|
||||||
|
setUserInfo(state, { payload }) {
|
||||||
|
state.info = payload;
|
||||||
|
},
|
||||||
|
// 修改 token
|
||||||
|
setToken(state, { payload }) {
|
||||||
|
state.token = payload || '';
|
||||||
|
},
|
||||||
|
},
|
||||||
|
subscriptions: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default UserModel;
|
3
src/pages/index.less
Normal file
3
src/pages/index.less
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
.title {
|
||||||
|
background: rgb(121, 242, 157);
|
||||||
|
}
|
9
src/pages/index.tsx
Normal file
9
src/pages/index.tsx
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import styles from './index.less';
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h1 className={styles.title}>index</h1>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
7
src/services/user.ts
Normal file
7
src/services/user.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import request from '@/utils/request';
|
||||||
|
|
||||||
|
export async function getUserInfo(): Promise<any> {
|
||||||
|
return request('/developer/info', {
|
||||||
|
method: 'get',
|
||||||
|
});
|
||||||
|
}
|
1
src/styles/index.less
Normal file
1
src/styles/index.less
Normal file
@ -0,0 +1 @@
|
|||||||
|
@import "./var.less";
|
15
src/styles/reset.less
Normal file
15
src/styles/reset.less
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
@import "var.less";
|
||||||
|
|
||||||
|
.ant-picker {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-pagination {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
&-total-text {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
90
src/styles/var.less
Normal file
90
src/styles/var.less
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
// 颜色
|
||||||
|
@S1: #25282a;
|
||||||
|
@S2: #1c21b8;
|
||||||
|
@S3: #2228e0;
|
||||||
|
@S4: #4046ff;
|
||||||
|
@S5: #9ca8ff;
|
||||||
|
@S6: #c9d2ff;
|
||||||
|
@M1: #000000;
|
||||||
|
@M2: #4a4a4a;
|
||||||
|
@M3: #7c7c7c;
|
||||||
|
@M4: #959595;
|
||||||
|
@M5: #c7c7c7;
|
||||||
|
@M6: #e0e0e0;
|
||||||
|
@M7: #f2f2f2;
|
||||||
|
@M8: #f9f9f9;
|
||||||
|
@M9: #ffffff;
|
||||||
|
@D1: #fac105;
|
||||||
|
@D2: #ffab24;
|
||||||
|
@D3: #ff6952;
|
||||||
|
@D4: #ff3c73;
|
||||||
|
@D5: #ee62d5;
|
||||||
|
@D6: #8475ff;
|
||||||
|
@D7: #4f73ff;
|
||||||
|
@D8: #148aff;
|
||||||
|
@D9: #0cc0c9;
|
||||||
|
@D10: #0cc991;
|
||||||
|
@D11: #83d615;
|
||||||
|
@D1-1: #fef8e5;
|
||||||
|
@D2-1: #fff6e9;
|
||||||
|
@D3-1: #fff0ed;
|
||||||
|
@D4-1: #ffebf1;
|
||||||
|
@D5-1: #fdeffa;
|
||||||
|
@D6-1: #f2f1ff;
|
||||||
|
@D7-1: #edf1ff;
|
||||||
|
@D8-1: #e7f3ff;
|
||||||
|
@D9-1: #e6f8f9;
|
||||||
|
@D10-1: #e6f9f3;
|
||||||
|
@D11-1: #f2fae7;
|
||||||
|
@F-info: #4766ff;
|
||||||
|
@F-success: #46cf84;
|
||||||
|
@F-warning: #ffa42e;
|
||||||
|
@F-red: #fa4646;
|
||||||
|
|
||||||
|
/* 字体 */
|
||||||
|
@Fs-1: 12px;
|
||||||
|
@Fs-2: 14px;
|
||||||
|
@Fs-3: 16px;
|
||||||
|
@Fs-4: 18px;
|
||||||
|
@Fs-5: 20px;
|
||||||
|
@Fs-6: 22px;
|
||||||
|
@Fs-7: 24px;
|
||||||
|
@Fs-8: 28px;
|
||||||
|
@Fs-9: 32px;
|
||||||
|
|
||||||
|
/* 行高 */
|
||||||
|
@Lh-1: 20px;
|
||||||
|
@Lh-2: 22px;
|
||||||
|
@Lh-3: 24px;
|
||||||
|
@Lh-4: 26px;
|
||||||
|
@Lh-5: 28px;
|
||||||
|
@Lh-6: 30px;
|
||||||
|
@Lh-7: 32px;
|
||||||
|
@Lh-8: 36px;
|
||||||
|
@Lh-9: 42px;
|
||||||
|
|
||||||
|
// 间距
|
||||||
|
@Sp-1: 2px;
|
||||||
|
@Sp-2: 4px;
|
||||||
|
@Sp-3: 8px;
|
||||||
|
@Sp-4: 10px;
|
||||||
|
@Sp-5: 12px;
|
||||||
|
@Sp-6: 16px;
|
||||||
|
@Sp-7: 20px;
|
||||||
|
@Sp-8: 24px;
|
||||||
|
@Sp-9: 30px;
|
||||||
|
@Sp-10: 32px;
|
||||||
|
@Sp-11: 40px;
|
||||||
|
|
||||||
|
// 阴影
|
||||||
|
@Sh-1: 0 0 8px 0 rgba(0, 0, 0, 0.05);
|
||||||
|
@Sh-2: 0 2px 8px 0 rgba(0, 0, 0, 0.1);
|
||||||
|
@Sh-3: 0 0 12px 0 rgba(0, 0, 0, 0.1);
|
||||||
|
@Sh-4: -4px 0 20px 0 rgba(0, 0, 0, 0.1);
|
||||||
|
@Sh-5: 0 2px 20px 0 rgba(0, 0, 0, 0.3);
|
||||||
|
|
||||||
|
// 圆角
|
||||||
|
@Ra-1: 2px;
|
||||||
|
@Ra-2: 3px;
|
||||||
|
@Ra-3: 6px;
|
||||||
|
@Ra-4: 10px;
|
0
src/utils/index.ts
Normal file
0
src/utils/index.ts
Normal file
66
src/utils/request.ts
Normal file
66
src/utils/request.ts
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
import axios from 'axios';
|
||||||
|
import { message } from 'antd';
|
||||||
|
import CodeMsg from '@/assets/data/code';
|
||||||
|
import { BaseResponse } from '@/interfaces/base';
|
||||||
|
|
||||||
|
export const DEFAULT_TIP_MESSAGE = '请求失败,请刷新重试';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 错误处理
|
||||||
|
* @param data {Object} 请求返回的信息
|
||||||
|
*/
|
||||||
|
export function handleError(data: BaseResponse): void {
|
||||||
|
const msg = CodeMsg[data.code] || data.msg || DEFAULT_TIP_MESSAGE;
|
||||||
|
message.error(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// create an axios instance
|
||||||
|
const service = axios.create({
|
||||||
|
baseURL: process.env.BASE_API, // api的base_url
|
||||||
|
// timeout: 5000, // request timeout
|
||||||
|
});
|
||||||
|
|
||||||
|
// request interceptor
|
||||||
|
service.interceptors.request.use(
|
||||||
|
config => {
|
||||||
|
// 防止 GET 请求缓存GET
|
||||||
|
if (config.method === 'get') {
|
||||||
|
const t = new Date().getTime();
|
||||||
|
config.params = config.params ? { ...config.params, t } : { t };
|
||||||
|
}
|
||||||
|
return config;
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
// Do something with request error
|
||||||
|
if (error.status === '504') {
|
||||||
|
message.error('网关超时,请重试!');
|
||||||
|
} else {
|
||||||
|
message.error(`网络异常[-${error.status}]`);
|
||||||
|
console.log(error); // for debug
|
||||||
|
}
|
||||||
|
Promise.reject(error);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// response interceptor
|
||||||
|
service.interceptors.response.use(
|
||||||
|
response => {
|
||||||
|
const res = response.data;
|
||||||
|
if (!res.success) {
|
||||||
|
if (res.code === '1007') {
|
||||||
|
// 登录失效
|
||||||
|
window.location.href = '/';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
handleError(res);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
handleError(error);
|
||||||
|
console.log(`err${error}`); // for debug
|
||||||
|
return Promise.reject(error);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
export default service;
|
29
src/wrappers/SecurityWrapper.tsx
Normal file
29
src/wrappers/SecurityWrapper.tsx
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import React, { useEffect } from 'react';
|
||||||
|
import { Redirect, connect, Dispatch, useLocation } from 'umi';
|
||||||
|
import { ConnectState } from '@/models/connect';
|
||||||
|
|
||||||
|
export interface SecurityWrapperProps {
|
||||||
|
token: string;
|
||||||
|
dispatch: Dispatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SecurityWrapper: React.FC<SecurityWrapperProps> = ({
|
||||||
|
token,
|
||||||
|
children,
|
||||||
|
}) => {
|
||||||
|
useEffect(() => {
|
||||||
|
// dispatch && dispatch({ type: 'user/fetchUser' });
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const isLogin = !!token;
|
||||||
|
const { pathname } = useLocation();
|
||||||
|
|
||||||
|
if (!isLogin && pathname !== '/') {
|
||||||
|
return <Redirect to="/" />;
|
||||||
|
}
|
||||||
|
return <>{children}</>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default connect(({ user }: ConnectState) => ({
|
||||||
|
token: user.token,
|
||||||
|
}))(SecurityWrapper);
|
34
tsconfig.json
Normal file
34
tsconfig.json
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "build/dist",
|
||||||
|
"module": "esnext",
|
||||||
|
"target": "esnext",
|
||||||
|
"lib": ["esnext", "dom"],
|
||||||
|
"sourceMap": true,
|
||||||
|
"baseUrl": ".",
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"noImplicitReturns": true,
|
||||||
|
"suppressImplicitAnyIndexErrors": true,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"allowJs": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"strict": true,
|
||||||
|
"paths": {
|
||||||
|
"@/*": ["./src/*"],
|
||||||
|
"@@/*": ["./src/.umi/*"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"node_modules",
|
||||||
|
"build",
|
||||||
|
"dist",
|
||||||
|
"scripts",
|
||||||
|
"src/.umi/*",
|
||||||
|
"webpack",
|
||||||
|
"jest"
|
||||||
|
]
|
||||||
|
}
|
5
typings.d.ts
vendored
Normal file
5
typings.d.ts
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
declare module '*.css';
|
||||||
|
declare module '*.less';
|
||||||
|
declare module '*.png';
|
||||||
|
declare module '*.jpeg';
|
||||||
|
declare module '*.jpg';
|
Loading…
Reference in New Issue
Block a user