Compare commits
7 Commits
Author | SHA1 | Date | |
---|---|---|---|
0b5e86a7ac | |||
3db1b3b98f | |||
462067ca96 | |||
e8f23283a2 | |||
12f85a51ed | |||
9d6340c83e | |||
cd2e8824e0 |
3
.commitlint.js
Normal file
3
.commitlint.js
Normal file
@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
extends: ["@nicecode/commit-lint"],
|
||||
};
|
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
|
3
.eslintignore
Normal file
3
.eslintignore
Normal file
@ -0,0 +1,3 @@
|
||||
build/
|
||||
dist/
|
||||
.umi
|
39
.eslintrc.js
Executable file
39
.eslintrc.js
Executable 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
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
|
37
.prettierrc.js
Normal file
37
.prettierrc.js
Normal 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
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';
|
||||
|
||||
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
77
.vscode/react.code-snippets
vendored
Normal 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
147
.vscode/settings.json
vendored
Normal 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
0
CHANGELOG.md
Normal file
35
README.md
35
README.md
@ -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
0
mock/.gitkeep
Normal file
72
package.json
Normal file
72
package.json
Normal 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
BIN
public/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 66 KiB |
2
src/app.ts
Normal file
2
src/app.ts
Normal file
@ -0,0 +1,2 @@
|
||||
import '@/styles/index.less';
|
||||
import '@/styles/reset.less';
|
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;
|
10
src/components/User/index.tsx
Normal file
10
src/components/User/index.tsx
Normal file
@ -0,0 +1,10 @@
|
||||
function User() {
|
||||
return (
|
||||
<>
|
||||
<div>个人中心</div>
|
||||
<div>退出登录</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default User;
|
28
src/interfaces/base.ts
Normal file
28
src/interfaces/base.ts
Normal 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;
|
||||
}
|
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 { 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;
|
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);
|
||||
}
|
||||
}
|
82
src/layouts/BasicLayout/index.tsx
Normal file
82
src/layouts/BasicLayout/index.tsx
Normal 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;
|
9
src/layouts/BlankLayout/index.tsx
Normal file
9
src/layouts/BlankLayout/index.tsx
Normal file
@ -0,0 +1,9 @@
|
||||
import React from 'react';
|
||||
|
||||
interface IBlankLayout {
|
||||
children: React.ReactNode
|
||||
}
|
||||
|
||||
const BlankLayout: React.FC<IBlankLayout> = ({ 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';
|
||||
|
||||
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;
|
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;
|
||||
}
|
||||
}
|
||||
}
|
22
src/layouts/WindowLayout/index.tsx
Normal file
22
src/layouts/WindowLayout/index.tsx
Normal 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
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;
|
5
src/pages/index.less
Normal file
5
src/pages/index.less
Normal file
@ -0,0 +1,5 @@
|
||||
.title {
|
||||
margin: 100px auto;
|
||||
text-align: center;
|
||||
// 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 function () {
|
||||
return (
|
||||
<div>
|
||||
<h1 className={styles.title}>welcome! there is nicecode!</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
52
src/utils/request.ts
Normal file
52
src/utils/request.ts
Normal 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;
|
30
src/wrappers/SecurityWrapper.tsx
Normal file
30
src/wrappers/SecurityWrapper.tsx
Normal 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
26
tsconfig.json
Normal 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
6
typings.d.ts
vendored
Normal 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
36
ytt.config.ts
Normal 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}`)
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
])
|
Loading…
Reference in New Issue
Block a user