Compare commits

...

7 Commits

Author SHA1 Message Date
dev
0b5e86a7ac feat:修改配置文件 2022-11-15 09:51:23 +08:00
dev
3db1b3b98f feat:修改配置文件 2022-11-15 09:36:05 +08:00
dev
462067ca96 feat: 接入ytt 2022-08-04 15:52:41 +08:00
dev
e8f23283a2 fix: 修改模板 2022-07-14 11:18:19 +08:00
dev
12f85a51ed fix:修改logo 2022-05-26 17:27:50 +08:00
dev
9d6340c83e 修复(hook): 修改hook 2022-05-26 16:24:15 +08:00
cd2e8824e0 feat: react-pc 2022-05-25 12:28:35 +08:00
50 changed files with 1342 additions and 34 deletions

3
.commitlint.js Normal file
View File

@ -0,0 +1,3 @@
module.exports = {
extends: ["@nicecode/commit-lint"],
};

16
.editorconfig Executable file
View 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

2
.env Normal file
View File

@ -0,0 +1,2 @@
BROWSER=none
ESLINT=1

3
.eslintignore Normal file
View File

@ -0,0 +1,3 @@
build/
dist/
.umi

39
.eslintrc.js Executable file
View File

@ -0,0 +1,39 @@
module.exports = {
extends: [
"alloy",
"alloy/react",
"alloy/typescript"
],
plugins: [
"@typescript-eslint/eslint-plugin"
],
parser: "@typescript-eslint/parser",
parserOptions: {
ecmaVersion: 2020,
},
"env": {
// 您的环境变量(包含多个预定义的全局变量)
// Your environments (which contains several predefined global variables)
//
// browser: true,
// node: true,
// mocha: true,
// jest: true,
// jquery: true
},
"globals": {
// 您的全局变量(设置为 false 表示它不允许被重新赋值)
// Your global variables (setting to false means it's not allowed to be reassigned)
//
// myGlobal: false
},
"rules": {
// 自定义您的规则
// Customize your rules
"react/jsx-no-useless-fragment": 0,
"@typescript-eslint/no-require-imports": 0,
"no-constant-binary-expression": 0,
"no-unused-private-class-members": 0,
"prefer-object-has-own": 0
}
};

23
.gitignore vendored Executable file
View 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
View File

@ -0,0 +1,8 @@
**/*.md
**/*.svg
**/*.ejs
**/*.html
package.json
.umi
.umi-production
.umi-test

37
.prettierrc.js Normal file
View File

@ -0,0 +1,37 @@
module.exports = {
// 一行最多 100 字符
printWidth: 100,
// 使用 4 个空格缩进
tabWidth: 4,
// 不使用缩进符,而使用空格
useTabs: false,
// 行尾需要有分号
semi: true,
// 使用单引号
singleQuote: true,
// 对象的 key 仅在必要时用引号
quoteProps: 'as-needed',
// jsx 不使用单引号,而使用双引号
jsxSingleQuote: false,
// 末尾不需要逗号
trailingComma: 'none',
// 大括号内的首尾需要空格
bracketSpacing: true,
// jsx 标签的反尖括号需要换行
jsxBracketSameLine: false,
// 箭头函数,只有一个参数的时候,也需要括号
arrowParens: 'always',
// 每个文件格式化的范围是文件的全部内容
rangeStart: 0,
rangeEnd: Infinity,
// 不需要写文件开头的 @prettier
requirePragma: false,
// 不需要自动在文件开头插入 @prettier
insertPragma: false,
// 使用默认的折行标准
proseWrap: 'preserve',
// 根据显示样式决定 html 要不要折行
htmlWhitespaceSensitivity: 'css',
// 换行符使用 lf
endOfLine: 'lf'
};

7
.umirc.pre.ts Normal file
View File

@ -0,0 +1,7 @@
import { defineConfig } from 'umi';
export default defineConfig({
define: {
'process.env.BASE_API': '/api',
},
});

10
.umirc.production.ts Normal file
View 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
View File

@ -0,0 +1,7 @@
import { defineConfig } from 'umi';
export default defineConfig({
define: {
'process.env.BASE_API': '/api',
},
});

7
.umirc.test.ts Normal file
View File

@ -0,0 +1,7 @@
import { defineConfig } from 'umi';
export default defineConfig({
define: {
'process.env.BASE_API': '/api',
},
});

107
.umirc.ts Normal file
View File

@ -0,0 +1,107 @@
import { defineConfig } from 'umi';
export default defineConfig({
favicon: 'http://localhost:8000',
hash: true,
dva: {
immer: true,
hmr: false,
},
webpack5: {},
mfsu: {},
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,
}
});

77
.vscode/react.code-snippets vendored Normal file
View File

@ -0,0 +1,77 @@
{
"函数组件模板": {
"prefix": "tsx",
"body": [
"// $CURRENT_YEAR-$CURRENT_MONTH-$CURRENT_DATE - by dev",
"\n",
"import { } from 'react'",
"import { connect, ConnectProps } from 'umi'",
"import {} from 'antd-mobile'",
"import styles from './index.less'",
"\n",
"interface I$1 extends ConnectProps {",
"}",
"\n",
"export default connect(({}: {}) => ({",
"}))((props: I$1) => {",
" return (",
" <div className={styles.$1}>$1</div>",
" )",
"})",
],
"description": "umi 函数组件模板"
},
"model模板": {
"prefix": "mts",
"body": [
"import { ImmerReducer, Effect } from 'umi';",
"import { SubscriptionsMapObject } from 'dva';",
"import { } from './serve';",
"\n",
"export interface $1ModelState {",
"}",
"\n",
"export interface $1ModelType {",
" namespace: '$1';",
" state: $1ModelState;",
" effects: {",
" };",
" reducers: {",
" save: ImmerReducer<$1ModelState>;",
" reset: ImmerReducer<$1ModelState>;",
" };",
" subscriptions: SubscriptionsMapObject;",
"}",
"\n",
"const initialState: $1ModelState = {",
"}",
"\n",
"const $1Model: $1ModelType = {",
" namespace: '$1',",
" state: initialState,",
" effects: {",
" // *getFormList({ payload }, { call, put }) {",
" // const response = yield call(getCaseForm, payload);",
" // yield put({",
" // type: 'save',",
" // payload: response,",
" // });",
" //},",
" },",
" reducers: {",
" save(state, { payload }: any) {",
" return { ...state, ...payload }",
" },",
" reset(state, { payload }: any) {",
" return { ...initialState }",
" }",
" },",
" subscriptions: {}",
"};",
"\n",
"export default $1Model;"
]
}
}

147
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,147 @@
// setting.json
{
"debug.console.fontFamily": "JetBrains Mono",
// debugAnyway:
"debug.onTaskErrors": "debugAnyway",
//
"editor.accessibilitySupport": "off",
//
"editor.cursorSmoothCaretAnimation": true,
"editor.find.addExtraSpaceOnTop": false,
//
"editor.fontLigatures": "'ss01', 'ss02', 'ss03', 'ss06', 'zero'",
//
"editor.glyphMargin": true,
//
"editor.inlineSuggest.enabled": true,
// 使
"editor.multiCursorModifier": "ctrlCmd",
"editor.tabSize": 2,
"editor.fontWeight": 440,
"editor.fontFamily": "JetBrains Mono, Menlo, Monaco, 'Courier New', monospace",
// ASCII
"editor.unicodeHighlight.ambiguousCharacters": false,
//
"editor.unicodeHighlight.invisibleCharacters": false,
// ESLint
"eslint.validate": [
"javascript",
"javascriptreact",
"vue",
"typescript",
"typescriptreact",
"html",
"css",
"scss",
"less",
"mpx",
"json",
"markdown"
],
// eslint
"eslint.quiet": true,
// eslint
"eslint.codeActionsOnSave.mode": "problems",
"eslint.format.enable": true,
//
"files.autoSaveDelay": 5000,
// LF
"files.eol": "\n",
//
"files.simpleDialog.enable": true,
// Git
"git.confirmSync": false,
"git.autofetch": true,
//
"security.workspace.trust.untrustedFiles": "open",
"vetur.validation.template": false,
//
"workbench.tree.indent": 10,
"workbench.iconTheme": "file-icons",
"workbench.startupEditor": "newUntitledFile",
"workbench.productIconTheme": "icons-carbon",
"workbench.colorTheme": "Community Material Theme Palenight High Contrast",
//
"workbench.editor.untitled.hint": "hidden",
//
"window.dialogStyle": "custom",
// macOS Sierra
"window.nativeTabs": true, // this is great, macOS only
// Linux Windows
"window.titleBarStyle": "custom",
//
"workbench.activityBar.visible": true,
//
// 使
//
"workbench.editor.closeOnFileDelete": true,
//
"workbench.editor.highlightModifiedTabs": true,
// antialiased:
"workbench.fontAliasing": "antialiased",
//
"workbench.list.smoothScrolling": true,
//
"workbench.sideBar.location": "left",
// Microsoft
// onlyEnabledExtensions:
"extensions.autoUpdate": "onlyEnabledExtensions",
//
"extensions.ignoreRecommendations": true,
//
"terminal.integrated.cursorBlinking": true,
//
"terminal.integrated.cursorStyle": "underline",
// 1-1000
"terminal.integrated.fontWeight": "300",
// ()
"terminal.integrated.persistentSessionReviveProcess": "never",
//
"terminal.integrated.tabs.enabled": true,
//
"explorer.confirmDelete": false,
//
"explorer.confirmDragAndDrop": false,
//
"explorer.experimental.fileNesting.enabled": true,
//
"explorer.experimental.fileNesting.expand": false,
//
"explorer.experimental.fileNesting.patterns": {
".gitignore": ".gitattributes, .gitmodules, .gitmessage, .mailmap, .git-blame*",
"*.js": "$(capture).js.map, $(capture).min.js, $(capture).d.ts",
"*.jsx": "$(capture).js",
"*.ts": "$(capture).js, $(capture).*.ts",
"*.tsx": "$(capture).ts",
"*.vue": "$(capture).*.ts, $(capture).*.js",
"index.d.ts": "*.d.ts",
"shims.d.ts": "*.d.ts",
"*.cpp": "$(capture).hpp, $(capture).h, $(capture).hxx",
"*.cxx": "$(capture).hpp, $(capture).h, $(capture).hxx",
"*.cc": "$(capture).hpp, $(capture).h, $(capture).hxx",
"*.c": "$(capture).h",
"go.mod": ".air*, go.sum",
"default.nix": "shell.nix",
"flake.nix": "flake.lock",
"BUILD.bazel": "*.bzl, *.bazel, *.bazelrc, bazel.rc, .bazelignore, .bazelproject, WORKSPACE",
"CMakeLists.txt": "*.cmake, *.cmake.in, .cmake-format.yaml, CMakePresets.json",
".clang-tidy": ".clang-format",
".env": "*.env, .env.*, env.d.ts",
"dockerfile": ".dockerignore, dockerfile*",
"package.json": ".browserslist*, .circleci*, .codecov, .commitlint*, .editorconfig, .eslint*, .firebase*, .flowconfig, .github*, .gitlab*, .gitpod*, .huskyrc*, .jslint*, .lintstagedrc*, .markdownlint*, .mocha*, .node-version, .nodemon*, .npm*, .nvmrc, .pm2*, .pnp.*, .pnpm*, .prettier*, .releaserc*, .sentry*, .stackblitz*, .styleci*, .stylelint*, .tazerc*, .textlint*, .tool-versions, .travis*, .vscode*, .watchman*, .xo-config*, .yamllint*, .yarnrc*, api-extractor.json, appveyor*, ava.config.*, azure-pipelines*, bower.json, build.config.*, commitlint*, crowdin*, cypress.json, dangerfile*, dprint.json, firebase.json, grunt*, gulp*, jasmine.*, jenkins*, jest.config.*, jsconfig.*, karma*, lerna*, lint-staged*, nest-cli.*, netlify*, nodemon*, nx.*, package-lock.json, playwright.config.*, pm2.*, pnpm*, prettier*, pullapprove*, puppeteer.config.*, renovate*, rollup.config.*, stylelint*, tsconfig.*, tsdoc.*, tslint*, tsup.config.*, turbo*, typedoc*, vercel*, vetur.config.*, vitest.config.*, webpack.config.*, workspace.json, xo.config.*, yarn*",
"rush.json": ".browserslist*, .circleci*, .codecov, .commitlint*, .editorconfig, .eslint*, .firebase*, .flowconfig, .github*, .gitlab*, .gitpod*, .huskyrc*, .jslint*, .lintstagedrc*, .markdownlint*, .mocha*, .node-version, .nodemon*, .npm*, .nvmrc, .pm2*, .pnp.*, .pnpm*, .prettier*, .releaserc*, .sentry*, .stackblitz*, .styleci*, .stylelint*, .tazerc*, .textlint*, .tool-versions, .travis*, .vscode*, .watchman*, .xo-config*, .yamllint*, .yarnrc*, api-extractor.json, appveyor*, ava.config.*, azure-pipelines*, bower.json, build.config.*, commitlint*, crowdin*, cypress.json, dangerfile*, dprint.json, firebase.json, grunt*, gulp*, jasmine.*, jenkins*, jest.config.*, jsconfig.*, karma*, lerna*, lint-staged*, nest-cli.*, netlify*, nodemon*, nx.*, package-lock.json, playwright.config.*, pm2.*, pnpm*, prettier*, pullapprove*, puppeteer.config.*, renovate*, rollup.config.*, stylelint*, tsconfig.*, tsdoc.*, tslint*, tsup.config.*, turbo*, typedoc*, vercel*, vetur.config.*, vitest.config.*, webpack.config.*, workspace.json, xo.config.*, yarn*",
"readme.*": "authors, backers.md, changelog*, citation*, code_of_conduct.md, codeowners, contributing.md, contributors, copying, credits, governance.md, history.md, license*, maintainers, readme*, security.md, sponsors.md",
"cargo.toml": ".clippy.toml, .rustfmt.toml, cargo.lock, clippy.toml, cross.toml, rust-toolchain.toml, rustfmt.toml",
"gemfile": ".ruby-version, gemfile.lock",
"composer.json": "composer.lock, phpunit.xml*, psalm*.xml",
"vite.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .htmlnanorc*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, cssnano.config.*, cypress.json, env.d.ts, htmlnanorc.*, index.html, jasmine.*, jest.config.*, jsconfig.*, karma*, playwright.config.*, postcss.config.*, puppeteer.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, unocss.config.*, vitest.config.*, webpack.config.*, windi.config.*",
"vue.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .htmlnanorc*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, cssnano.config.*, cypress.json, env.d.ts, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, playwright.config.*, postcss.config.*, puppeteer.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, unocss.config.*, vitest.config.*, webpack.config.*, windi.config.*",
"nuxt.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .htmlnanorc*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, cssnano.config.*, cypress.json, env.d.ts, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, playwright.config.*, postcss.config.*, puppeteer.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, unocss.config.*, vitest.config.*, webpack.config.*, windi.config.*",
"next.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .htmlnanorc*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, cssnano.config.*, cypress.json, env.d.ts, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, next-env.d.ts, playwright.config.*, postcss.config.*, puppeteer.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, unocss.config.*, vitest.config.*, webpack.config.*, windi.config.*",
"svelte.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .htmlnanorc*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, cssnano.config.*, cypress.json, env.d.ts, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, mdsvex.config.js, playwright.config.*, postcss.config.*, puppeteer.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, unocss.config.*, vitest.config.*, webpack.config.*, windi.config.*",
"remix.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .htmlnanorc*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, cssnano.config.*, cypress.json, env.d.ts, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, playwright.config.*, postcss.config.*, puppeteer.config.*, remix.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, unocss.config.*, vitest.config.*, webpack.config.*, windi.config.*"
},
"[typescript]": {
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
}
}

0
CHANGELOG.md Normal file
View File

View File

@ -1,34 +1 @@
## 目前已有脚手架列表
| 名称 | 说明 | 技术栈 |
| ------- | --------------------------- | --------------------- |
| 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 ${项目名称}
```
# react-template 模板

0
mock/.gitkeep Normal file
View File

72
package.json Normal file
View File

@ -0,0 +1,72 @@
{
"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",
"cz": "git add . && git cz"
},
"config": {
"commitizen": {
"path": "@nicecode/commit"
}
},
"husky": {
"hooks": {
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
}
},
"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/icons": "^4.7.0",
"@ant-design/pro-components": "^1.1.2",
"@ant-design/pro-layout": "^6.15.4",
"antd": "^4.20.6",
"classnames": "^2.2.6",
"dayjs": "^1.11.2",
"js-cookie": "^2.2.1",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"umi": "^3.5.15",
"yapi-to-typescript": "^3.34.1"
},
"devDependencies": {
"@nicecode/commit-lint": "^0.1.2",
"@types/classnames": "^2.2.10",
"@typescript-eslint/eslint-plugin": "^5.26.0",
"@typescript-eslint/parser": "^5.26.0",
"@umijs/preset-react": "1.x",
"@umijs/test": "^3.0.16",
"babel-plugin-transform-remove-console": "^6.9.4",
"commitlint": "^17.0.1",
"cross-env": "^7.0.2",
"eslint": "^7.16.0",
"eslint-config-alloy": "^4.5.1",
"eslint-plugin-react": "^7.30.0",
"husky": "^8.0.1",
"lint-staged": "^10.0.7",
"prettier": "^1.19.1",
"typescript": "^4.1.3",
"yorkie": "^2.0.0"
}
}

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

2
src/app.ts Normal file
View File

@ -0,0 +1,2 @@
import '@/styles/index.less';
import '@/styles/reset.less';

2
src/assets/data/code.ts Normal file
View File

@ -0,0 +1,2 @@
// 业务错误码
export default {};

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -0,0 +1,3 @@
import { PageLoading } from '@ant-design/pro-layout';
export default PageLoading;

View File

@ -0,0 +1,10 @@
function User() {
return (
<>
<div></div>
<div>退</div>
</>
);
}
export default User;

28
src/interfaces/base.ts Normal file
View File

@ -0,0 +1,28 @@
import React from 'react';
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;
}

View 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;

View File

@ -0,0 +1,48 @@
import React from 'react';
import { history } from 'umi';
import { Button } from 'antd';
import { ButtonProps } from 'antd/lib/button';
import { HomeOutlined } from '@ant-design/icons';
import classnames from 'classnames';
import './index.less';
interface BreadcrumbItemProps extends ButtonProps {
path: string;
}
const BreadcrumbItem = ({
path,
children,
className,
...rest
}: BreadcrumbItemProps) => {
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}
>
<HomeOutlined />
</Button>
);
BreadcrumbItem.Root = RootItem;
export default BreadcrumbItem;

View 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);
}
}

View File

@ -0,0 +1,82 @@
import React from 'react';
import { history, Link } from 'umi';
import { EnterOutlined } from '@ant-design/icons';
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';
interface IBasicLayout {
children: React.ReactNode
}
const BasicLayout: React.FC<IBasicLayout> = ({ children, ...rest }: any) => {
const iconMap = {
EnterOutlined: <EnterOutlined />,
};
// 带子菜单的一级导航
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={require('@/assets/images/login.png')}
title="nicecode"
siderWidth={180}
fixedHeader
fixSiderbar
onMenuHeaderClick={() => history.push('/')}
subMenuItemRender={renderSubMenuItem}
menuItemRender={renderMenuItem}
headerContentRender={renderHeaderContent}
// rightContentRender={renderUserAvatar}
{...rest}
>
{children}
</ProLayout>
);
};
export default BasicLayout;

View File

@ -0,0 +1,9 @@
import React from 'react';
interface IBlankLayout {
children: React.ReactNode
}
const BlankLayout: React.FC<IBlankLayout> = ({ children }) => (<>{children}</>);
export default BlankLayout;

View File

@ -0,0 +1,33 @@
import { history } from 'umi';
import { Image, Divider } from 'antd';
import User from '@/components/User';
import './index.less';
function 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;

View 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;
}
}
}

View File

@ -0,0 +1,22 @@
import React from 'react';
import Header from './Header';
import './index.less';
interface IWindowLayout {
children: React.ReactNode
}
const WindowLayout: React.FC<IWindowLayout> = ({ 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
View File

@ -0,0 +1 @@
export default {};

5
src/models/connect.ts Normal file
View File

@ -0,0 +1,5 @@
import { UserModelState } from './user';
export interface ConnectState {
user: UserModelState;
}

56
src/models/user.ts Normal file
View 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;

5
src/pages/index.less Normal file
View File

@ -0,0 +1,5 @@
.title {
margin: 100px auto;
text-align: center;
// background: rgb(121, 242, 157);
}

9
src/pages/index.tsx Normal file
View File

@ -0,0 +1,9 @@
import styles from './index.less';
export default function () {
return (
<div>
<h1 className={styles.title}>welcome! there is nicecode!</h1>
</div>
);
}

7
src/services/user.ts Normal file
View 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
View File

@ -0,0 +1 @@
@import './var.less';

15
src/styles/reset.less Normal file
View 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
View 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
View File

52
src/utils/request.ts Normal file
View File

@ -0,0 +1,52 @@
import { extend } from 'umi-request';
import { message } from 'antd';
import CodeMsg from '@/assets/data/code';
import { BaseResponse } from '@/interfaces/base';
/**
*
* @param data {Object}
*/
export function handleError(data: BaseResponse) {
const msg = CodeMsg[data.code] || data.msg || CodeMsg['DEFAULT_TIP_MESSAGE'];
message.error(msg);
}
// create an axios instance
const service = extend({
baseURL: process.env.BASE_API, // api的base_url
timeout: 1000,
mode: 'cors',
errorHandler: (error: any) => handleError(error),
});
// request interceptor
service.interceptors.request.use(
(url: string, config: any) => {
// 防止 GET 请求缓存GET
if (config.method === 'GET') {
const t = new Date().getTime();
config.params = config.params ? { ...config.params, t } : { t };
}
return config;
}
);
// response interceptor
service.interceptors.response.use(
async (response: any) => {
const res = await response.clone().json();
if (Number(res.code) !== 200) {
if (Number(res.code) === 1007) {
// 登录失效
window.location.href = '/';
return Promise.resolve();
}
handleError(res);
return Promise.resolve();
}
return res.data;
}
);
export default service;

View File

@ -0,0 +1,30 @@
import React, { useEffect } from 'react';
import { Redirect, connect, Dispatch, useLocation } from 'umi';
import { ConnectState } from '@/models/connect';
export interface SecurityWrapperProps {
token: string;
dispatch: Dispatch;
children: React.ReactNode
}
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);

26
tsconfig.json Normal file
View File

@ -0,0 +1,26 @@
{
"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"]
}

6
typings.d.ts vendored Normal file
View File

@ -0,0 +1,6 @@
declare module '*.css';
declare module '*.less';
declare module '*.png';
declare module '*.jpeg';
declare module '*.jpg';
declare module 'immer'

36
ytt.config.ts Normal file
View File

@ -0,0 +1,36 @@
import { defineConfig } from 'yapi-to-typescript'
export default defineConfig([
{
serverUrl: 'http://yapi.jzxer.cn',
typesOnly: false,
target: 'typescript',
reactHooks: {
enabled: false,
},
prodEnvName: 'production',
outputFilePath: 'src/api/index.ts',
requestFunctionFilePath: 'src/utils/request.ts',
dataKey: 'data',
projects: [
{
token: '',
categories: [
{
id: 0,
getRequestFunctionName(interfaceInfo, changeCase) {
// 以接口全路径生成请求函数名
return changeCase.camelCase(interfaceInfo.path)
// 若生成的请求函数名存在语法关键词报错、或想通过某个关键词触发 IDE 自动引入提示,可考虑加前缀,如:
// return changeCase.camelCase(`api_${interfaceInfo.path}`)
// 若生成的请求函数名有重复报错,可考虑将接口请求方式纳入生成条件,如:
// return changeCase.camelCase(`${interfaceInfo.method}_${interfaceInfo.path}`)
},
},
],
},
],
},
])