├── .github
├── ISSUE_TEMPLATE
│ ├── BUG_REPORT.md
│ └── FEATURE_REQUEST.md
└── workflows
│ └── ci.yml
├── .gitignore
├── .husky
└── pre-commit
├── .prettierignore
├── .prettierrc
├── CHANGELOG.md
├── LICENSE
├── README.md
├── create-uiw-admin
├── .gitignore
├── .prettierignore
├── .prettierrc
├── README.md
├── package.json
├── renovate.json
├── src
│ ├── cli.ts
│ └── utils.ts
├── test
│ └── cli.test.ts
└── tsconfig.json
├── eslint-packages
└── config
│ ├── README.md
│ ├── index.js
│ └── package.json
├── examples
├── base
│ ├── .editorconfig
│ ├── .gitignore
│ ├── .prettierignore
│ ├── .prettierrc.js
│ ├── .stackblitzrc
│ ├── README.md
│ ├── config
│ │ ├── .kktprc.ts
│ │ └── routes.json
│ ├── mocker
│ │ ├── auth
│ │ │ └── index.js
│ │ ├── demo.js
│ │ ├── index.js
│ │ ├── login.js
│ │ └── selectPage.js
│ ├── package.json
│ ├── public
│ │ ├── favicon.ico
│ │ └── index.html
│ ├── sandbox.config.json
│ ├── src
│ │ ├── assets
│ │ │ ├── head.png
│ │ │ ├── index.js
│ │ │ ├── logo-dark.svg
│ │ │ └── logo-light.svg
│ │ ├── layouts
│ │ │ ├── BasicLayout.tsx
│ │ │ ├── UserLayout.tsx
│ │ │ └── logo.svg
│ │ ├── models
│ │ │ ├── Doc
│ │ │ │ └── doc.ts
│ │ │ ├── demo.ts
│ │ │ ├── global.ts
│ │ │ ├── home.ts
│ │ │ └── login.ts
│ │ ├── pages
│ │ │ ├── Dashboard
│ │ │ │ ├── index.tsx
│ │ │ │ └── models
│ │ │ │ │ └── index.ts
│ │ │ ├── Demo
│ │ │ │ ├── Detail
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── items.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ └── models
│ │ │ │ │ └── index.ts
│ │ │ ├── Form
│ │ │ │ ├── index.less
│ │ │ │ ├── index.tsx
│ │ │ │ ├── items.tsx
│ │ │ │ └── models
│ │ │ │ │ └── index.ts
│ │ │ ├── TableList
│ │ │ │ └── index.tsx
│ │ │ └── ceshi.tsx
│ │ ├── react-app-env.d.ts
│ │ ├── routesOutletElement
│ │ │ ├── index.css
│ │ │ └── index.tsx
│ │ └── servers
│ │ │ ├── demo.ts
│ │ │ └── index.ts
│ └── tsconfig.json
└── website
│ ├── README.md
│ ├── config
│ ├── .kktprc.ts
│ └── routes.js
│ ├── package.json
│ ├── public
│ ├── index.html
│ └── logo.svg
│ ├── src
│ ├── components
│ │ ├── Layouts
│ │ │ ├── Menu
│ │ │ │ ├── index.tsx
│ │ │ │ └── style.ts
│ │ │ ├── Navbar
│ │ │ │ ├── index.tsx
│ │ │ │ └── style.ts
│ │ │ └── index
│ │ │ │ ├── index.tsx
│ │ │ │ └── style.ts
│ │ ├── Loading
│ │ │ ├── index.tsx
│ │ │ └── style.ts
│ │ └── Preview
│ │ │ ├── index.tsx
│ │ │ ├── nodes
│ │ │ ├── toc.less
│ │ │ └── toc.tsx
│ │ │ ├── useHyperlink.tsx
│ │ │ └── useMdData.ts
│ ├── global.css
│ ├── index.less
│ ├── menus.ts
│ ├── pages
│ │ ├── auth
│ │ │ ├── README.md
│ │ │ └── index.tsx
│ │ ├── authorized
│ │ │ └── index.tsx
│ │ ├── basic-layouts
│ │ │ └── index.tsx
│ │ ├── components
│ │ │ ├── ProDrawer.tsx
│ │ │ ├── ProForm.tsx
│ │ │ ├── Protable.tsx
│ │ │ ├── Skeleton.tsx
│ │ │ └── index.tsx
│ │ ├── config
│ │ │ └── index.tsx
│ │ ├── document-title
│ │ │ └── index.tsx
│ │ ├── eslint-config
│ │ │ ├── README.md
│ │ │ └── index.tsx
│ │ ├── example
│ │ │ ├── index.module.css
│ │ │ └── index.tsx
│ │ ├── exceptions
│ │ │ └── index.tsx
│ │ ├── home
│ │ │ ├── index.tsx
│ │ │ └── style.ts
│ │ ├── layout-tabs
│ │ │ └── index.tsx
│ │ ├── mocker
│ │ │ ├── README.md
│ │ │ └── index.tsx
│ │ ├── models
│ │ │ ├── README.md
│ │ │ └── index.tsx
│ │ ├── navbar
│ │ │ └── index.tsx
│ │ ├── newPages
│ │ │ ├── README.md
│ │ │ └── index.tsx
│ │ ├── plugins
│ │ │ └── index.tsx
│ │ ├── proxy
│ │ │ ├── README.md
│ │ │ └── index.tsx
│ │ ├── quick-start
│ │ │ ├── README.md
│ │ │ └── index.tsx
│ │ ├── request
│ │ │ ├── README.md
│ │ │ └── index.tsx
│ │ ├── router-control
│ │ │ └── index.tsx
│ │ ├── user-login
│ │ │ ├── Example.tsx
│ │ │ ├── Examples.tsx
│ │ │ ├── index.tsx
│ │ │ ├── index2.tsx
│ │ │ └── logo-large.svg
│ │ └── utils
│ │ │ └── index.tsx
│ └── react-app-env.d.ts
│ └── tsconfig.json
├── lerna.json
├── package.json
├── packages
├── authorized
│ ├── README.md
│ ├── package.json
│ ├── src
│ │ ├── Auth.tsx
│ │ └── index.tsx
│ └── tsconfig.json
├── basic-layouts
│ ├── README.md
│ ├── package.json
│ ├── src
│ │ ├── components
│ │ │ ├── BodyContent
│ │ │ │ └── index.tsx
│ │ │ ├── Breadcrumb
│ │ │ │ ├── index.css
│ │ │ │ └── index.tsx
│ │ │ ├── FullScreen
│ │ │ │ └── index.tsx
│ │ │ ├── HeaderRightMenu
│ │ │ │ ├── index.css
│ │ │ │ └── index.tsx
│ │ │ ├── IconBox
│ │ │ │ ├── index.css
│ │ │ │ └── index.tsx
│ │ │ ├── LogoHeader
│ │ │ │ └── index.tsx
│ │ │ ├── Menu
│ │ │ │ ├── Search.tsx
│ │ │ │ └── index.tsx
│ │ │ └── index.ts
│ │ ├── hook.ts
│ │ ├── index.css
│ │ ├── index.tsx
│ │ ├── useLayouts.tsx
│ │ └── utils.ts
│ └── tsconfig.json
├── components
│ ├── README.md
│ ├── __tests__
│ │ └── components.test.js
│ ├── package.json
│ ├── src
│ │ ├── ProDrawer
│ │ │ ├── README.md
│ │ │ └── index.tsx
│ │ ├── ProForm
│ │ │ ├── README.md
│ │ │ ├── formdom.tsx
│ │ │ ├── hooks
│ │ │ │ ├── store.tsx
│ │ │ │ └── useForm.tsx
│ │ │ ├── index.tsx
│ │ │ ├── readform.tsx
│ │ │ ├── style
│ │ │ │ └── form-item.css
│ │ │ ├── type.ts
│ │ │ ├── utils
│ │ │ │ └── index.tsx
│ │ │ └── widgets
│ │ │ │ ├── CheckBox
│ │ │ │ └── index.tsx
│ │ │ │ ├── SearchTree
│ │ │ │ └── index.tsx
│ │ │ │ ├── SelectMultiple
│ │ │ │ └── index.tsx
│ │ │ │ ├── Upload
│ │ │ │ └── index.tsx
│ │ │ │ └── index.tsx
│ │ ├── ProTable
│ │ │ ├── BaseForm.tsx
│ │ │ ├── BaseTable.tsx
│ │ │ ├── README.md
│ │ │ ├── hooks.ts
│ │ │ ├── index.css
│ │ │ ├── index.tsx
│ │ │ ├── style
│ │ │ │ └── index.less
│ │ │ ├── types.ts
│ │ │ ├── useSelections.ts
│ │ │ ├── useTable.ts
│ │ │ └── widgets
│ │ │ │ ├── Radio.tsx
│ │ │ │ ├── SearchTree.tsx
│ │ │ │ └── Select.tsx
│ │ ├── Skeleton
│ │ │ ├── README.md
│ │ │ └── index.tsx
│ │ ├── form
│ │ │ ├── index.tsx
│ │ │ ├── interface.ts
│ │ │ └── utils
│ │ │ │ └── index.ts
│ │ └── index.tsx
│ └── tsconfig.json
├── config
│ ├── README.md
│ ├── package.json
│ ├── src
│ │ ├── index.ts
│ │ └── uitls.ts
│ └── tsconfig.json
├── document-title
│ ├── README.md
│ ├── package.json
│ ├── src
│ │ └── index.tsx
│ ├── tsconfig copy.json
│ └── tsconfig.json
├── exceptions
│ ├── README.md
│ ├── package.json
│ ├── src
│ │ ├── Exceptions
│ │ │ ├── 403.tsx
│ │ │ ├── 404.tsx
│ │ │ ├── 500.tsx
│ │ │ ├── asset
│ │ │ │ ├── 403.svg
│ │ │ │ ├── 404.svg
│ │ │ │ └── 500.svg
│ │ │ └── styles
│ │ │ │ └── index.css
│ │ └── index.ts
│ └── tsconfig.json
├── layout-tabs
│ ├── README.md
│ ├── package.json
│ ├── src
│ │ ├── index.tsx
│ │ ├── styles
│ │ │ └── index.css
│ │ └── utils.ts
│ └── tsconfig.json
├── markdown-navbar
│ ├── README.md
│ ├── package.json
│ ├── src
│ │ ├── index.tsx
│ │ └── style.css
│ └── tsconfig.json
├── models
│ ├── README.md
│ ├── package.json
│ ├── src
│ │ ├── index.ts
│ │ └── react-app-env.d.ts
│ └── tsconfig.json
├── plugins
│ ├── README.md
│ ├── package.json
│ ├── src
│ │ ├── index.ts
│ │ ├── initIndex
│ │ │ ├── index.ts
│ │ │ └── temp.ts
│ │ ├── rematch
│ │ │ ├── index.ts
│ │ │ ├── temp.ts
│ │ │ └── utils.ts
│ │ ├── routes
│ │ │ ├── index.ts
│ │ │ └── temp.ts
│ │ └── utils
│ │ │ ├── babel.ts
│ │ │ ├── index.ts
│ │ │ ├── interface.ts
│ │ │ └── rematch.ts
│ └── tsconfig.json
├── router-control
│ ├── README.md
│ ├── package.json
│ ├── src
│ │ └── index.ts
│ └── tsconfig.json
├── uiw-admin
│ ├── LICENSE
│ ├── README.md
│ ├── package.json
│ └── tsconfig.json
├── user-login
│ ├── README.md
│ ├── package.json
│ ├── src
│ │ ├── assets
│ │ │ ├── bg.jpeg
│ │ │ └── r2g7rm.jpg
│ │ ├── index.tsx
│ │ ├── react-app-env.d.ts
│ │ └── styles
│ │ │ └── index.css
│ └── tsconfig.json
└── utils
│ ├── README.md
│ ├── package.json
│ ├── src
│ ├── cookies.ts
│ ├── index.ts
│ ├── request.ts
│ └── utils.ts
│ └── tsconfig.json
├── renovate.json
├── script
└── copy.js
├── test
└── copy.test.ts
└── tsconfig.json
/.github/ISSUE_TEMPLATE/BUG_REPORT.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: 错误报告(Bug Report)
3 | about: 当出现问题时提交报告以便修复!
4 | title: "[TimePicker<组件名称>]: 清晰简洁地一句话描述错误"
5 | labels: bug,question
6 | ---
7 |
8 | 注意:根据下面内容复现错误问题,以方便测试。
9 |
10 | ### 描述错误
11 |
12 | 清晰简洁地描述错误是什么。
13 |
14 | ### 错误复现
15 |
16 | 重现行为的步骤:
17 |
18 | 1. 转到“...”
19 | 2. 点击“....”
20 | 3. 向下滚动到“....”
21 | 4. 查看错误
22 |
23 | ### 提供在线重现示例
24 |
25 | 尽可能的提供一个在线示例,帮助我们快速解决问题。
26 |
27 | [](https://codesandbox.io/)
28 |
29 | ### 预期行为
30 |
31 | 对您期望发生的事情进行清晰简洁的描述。
32 |
33 | ### 截图
34 |
35 | 如果适用,请添加屏幕截图以帮助解释您的问题。
36 |
37 | ### 桌面(请填写以下信息):
38 |
39 | - UIW:[例如 v4.13.4]
40 | - 操作系统:[例如 macOS]
41 | - 浏览器:[例如 火狐、Chrome、Safari]
42 | - 版本和构建:[例如 59.0.2(64 位)]
43 |
44 | ### 智能手机(请填写以下信息):
45 |
46 | - 设备:[例如 iPhone 6]
47 | - 操作系统:[例如 iOS8.1]
48 | - 浏览器 [例如 股票浏览器,野生动物园]
49 | - 版本 [例如 22]
50 |
51 | ### 附加上下文
52 |
53 | 在此处添加有关该问题的任何其他上下文。
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: 功能要求(Feature Request)
3 | about: 为 uiw-admin 组件推荐一个功能(添加一个组件,一个组件 API...)!
4 | labels: feature,enhancement
5 | ---
6 |
7 | **您的功能请求是否与问题有关?请描述。**
8 |
9 | 对推荐的新功能,添加清晰简洁的描述。前任。当 [...]
10 |
11 | **描述您想要的解决方案**
12 |
13 | 对您想要发生的事情的清晰简洁的描述。
14 |
15 | **描述您考虑过的替代方案**
16 |
17 | 对您考虑过的任何替代解决方案或功能的清晰简洁的描述。
18 |
19 | **附加上下文**
20 |
21 | 在此处添加有关功能请求的任何其他上下文或屏幕截图。
22 |
23 | ### 问题清单
24 |
25 | 完成每个步骤后,在方框中打一个 x。您也可以在创建问题后填写这些内容。如果您不确定其中的任何一个,请随时询问。我们是来帮忙的!这只是提醒我们在回应问题之前要寻找什么。
26 |
27 | - [ ] 我已经检查过其他类似的问题
28 | - [ ] 我已经解释了为什么这个改变很重要
29 | - [ ] 我添加了必要的文件(如果适用)
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | dist
2 | build
3 | lib
4 | esm
5 | coverage
6 | node_modules
7 | npm-debug.log*
8 | yarn-debug.log*
9 | yarn-error.log*
10 | package-lock.json
11 | yarn.lock
12 | baseJS
13 | basejs
14 | .kktp
15 | .uiw
16 |
17 | *.lerna_backup
18 | .DS_Store
19 | .cache
20 | .vscode
21 | .idea
22 | .snap
23 | .env
24 |
25 | *.bak
26 | *.tem
27 | *.temp
28 | #.swp
29 | *.*~
30 | ~*.*
31 |
32 | # IDEA
33 | *.iml
34 | *.ipr
35 | *.iws
--------------------------------------------------------------------------------
/.husky/pre-commit:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | . "$(dirname "$0")/_/husky.sh"
3 |
4 | npx --no-install lint-staged
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | **/*.md
2 | **/*.svg
3 | **/*.ejs
4 | **/*.html
5 | examples/website/build
6 | package.json
7 | dist
8 | lib
9 | .kktp
10 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "trailingComma": "all",
4 | "printWidth": 80,
5 | "overrides": [
6 | {
7 | "files": ".prettierrc",
8 | "options": { "parser": "json" }
9 | }
10 | ]
11 | }
12 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT LICENSE
2 |
3 | Copyright (c) 2020-present 尼好
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining
6 | a copy of this software and associated documentation files (the
7 | "Software"), to deal in the Software without restriction, including
8 | without limitation the rights to use, copy, modify, merge, publish,
9 | distribute, sublicense, and/or sell copies of the Software, and to
10 | permit persons to whom the Software is furnished to do so, subject to
11 | the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be
14 | included in all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | packages/uiw-admin/README.md
--------------------------------------------------------------------------------
/create-uiw-admin/.gitignore:
--------------------------------------------------------------------------------
1 | build
2 | lib
3 | cjs
4 | esm
5 | node_modules
6 | coverage
7 | npm-debug.log*
8 | package-lock.json
9 |
10 | .eslintcache
11 | .DS_Store
12 | .cache
13 | .rdoc-dist
14 |
15 | *.log
16 | *.bak
17 | *.tem
18 | *.temp
19 | #.swp
20 | *.*~
21 | ~*.*
--------------------------------------------------------------------------------
/create-uiw-admin/.prettierignore:
--------------------------------------------------------------------------------
1 | **/*.md
2 | **/*.svg
3 | **/*.ejs
4 | **/*.html
5 |
6 | package.json
7 | dist
8 | build
9 | lib
10 | esm
11 |
--------------------------------------------------------------------------------
/create-uiw-admin/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "trailingComma": "all",
4 | "printWidth": 80,
5 | "overrides": [
6 | {
7 | "files": ".prettierrc",
8 | "options": { "parser": "json" }
9 | }
10 | ]
11 | }
12 |
--------------------------------------------------------------------------------
/create-uiw-admin/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | Creates a [`uiw-admin`](https://github.com/uiwjs/uiw-admin) application using the command line.
27 |
28 | ## Usage
29 |
30 | ```shell
31 | # npm 6.x
32 | $ npm init uiw-admin my-app --example uiw-admin-ts
33 | # npm 7+, extra double-dash is needed:
34 | $ npm init uiw-admin my-app -- --example uiw-admin-ts
35 |
36 | $ yarn create uiw-admin [appName]
37 | # or npm
38 | $ npm create uiw-admin my-app
39 | # or npx
40 | $ npx create-uiw-admin my-app
41 | ```
42 |
43 | ## Command Help
44 |
45 | Below is a help of commands you might find useful. The example download is from https://uiwjs.github.io/uiw-admin/zip/
46 |
47 | ```bash
48 | Usage: create-uiw-admin [options] [--help|h]
49 |
50 | Options:
51 |
52 | --version, -v Show version number
53 | --help, -h Displays help information.
54 | --output, -o Output directory.
55 | --example, -e Example from: https://uiwjs.github.io/uiw-admin/zip/, default: "uiw-admin-ts"
56 | --path, -p Specify the download target git address.
57 | default: "https://uiwjs.github.io/uiw-admin/zip/"
58 |
59 | Example:
60 |
61 | yarn create uiw-admin appName
62 | npx create-uiw-admin my-app
63 | npm create uiw-admin my-app
64 | npm create uiw-admin my-app -f
65 | npm create uiw-admin my-app -p https://uiwjs.github.io/uiw-admin/zip/
66 |
67 | Copyright 2021
68 | ```
69 |
70 | ## License
71 |
72 | [MIT © Kenny Wong](https://github.com/jaywcjlove)
73 |
--------------------------------------------------------------------------------
/create-uiw-admin/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "create-uiw-admin",
3 | "version": "6.1.9",
4 | "description": "Creates a antdp application using the command line.",
5 | "homepage": "https://uiwjs.github.io/uiw-admin",
6 | "author": "Kenny Wong (https://github.com/jaywcjlove)",
7 | "main": "lib/index.js",
8 | "license": "MIT",
9 | "repository": {
10 | "type": "git",
11 | "url": "https://github.com/uiwjs/uiw-admin"
12 | },
13 | "bin": {
14 | "create-uiw-admin": "lib/cli.js"
15 | },
16 | "scripts": {
17 | "build": "tsbb build --disable-babel --file-names src/cli.ts",
18 | "watch": "tsbb watch --disable-babel --file-names src/cli.ts",
19 | "prettier": "prettier --write '**/*.{js,jsx,tsx,ts,md,json}'",
20 | "coverage": "tsbb test --coverage --detectOpenHandles",
21 | "test": "tsbb test --detectOpenHandles"
22 | },
23 | "files": [
24 | "lib",
25 | "src"
26 | ],
27 | "jest": {
28 | "testMatch": [
29 | "/test/*.{ts,tsx}"
30 | ]
31 | },
32 | "keywords": [
33 | "tsbb",
34 | "create-tsbb",
35 | "react",
36 | "redux",
37 | "rematch",
38 | "uiw",
39 | "redux-saga",
40 | "framework",
41 | "frontend"
42 | ],
43 | "devDependencies": {
44 | "prettier": "^2.7.0",
45 | "pretty-quick": "~3.1.3",
46 | "tsbb": "^4.0.5"
47 | },
48 | "dependencies": {
49 | "create-kkt": "3.0.0"
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/create-uiw-admin/renovate.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["config:base"]
3 | }
4 |
--------------------------------------------------------------------------------
/create-uiw-admin/src/cli.ts:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | import { run } from './utils';
4 |
5 | try {
6 | run();
7 | } catch (error) {
8 | console.log(`\x1b[31m${error.message}\x1b[0m`);
9 | console.log(error);
10 | process.exit(1);
11 | }
12 |
--------------------------------------------------------------------------------
/create-uiw-admin/src/utils.ts:
--------------------------------------------------------------------------------
1 | import minimist from 'minimist';
2 | import { create } from 'create-kkt';
3 |
4 | export async function run(): Promise {
5 | const argvs = minimist(process.argv.slice(2), {
6 | alias: {
7 | output: 'o',
8 | version: 'v',
9 | force: 'f',
10 | path: 'p',
11 | example: 'e',
12 | },
13 | default: {
14 | path: 'https://uiwjs.github.io/uiw-admin/zip/',
15 | output: '.',
16 | force: false,
17 | example: 'uiw-admin-ts',
18 | },
19 | });
20 | if (argvs.h || argvs.help) {
21 | console.log(helpCli);
22 | return;
23 | }
24 | const { version } = require('../package.json');
25 | if (argvs.v || argvs.version) {
26 | console.log(`\n create-uiw-admin v${version}\n`);
27 | return;
28 | }
29 | argvs.appName = argvs._[0];
30 | argvs.example = argvs.e = String(argvs.example).toLocaleLowerCase();
31 | await create(argvs, helpExample);
32 | }
33 |
34 | export const helpExample: string = `Example:
35 |
36 | \x1b[35myarn\x1b[0m create uiw-admin \x1b[33mappName\x1b[0m
37 | \x1b[35mnpx\x1b[0m create-uiw-admin \x1b[33mmy-app\x1b[0m
38 | \x1b[35mnpm\x1b[0m create uiw-admin \x1b[33mmy-app\x1b[0m
39 | \x1b[35mnpm\x1b[0m create uiw-admin \x1b[33mmy-app\x1b[0m -f
40 | \x1b[35mnpm\x1b[0m create uiw-admin \x1b[33mmy-app\x1b[0m -p \x1b[34mhttps://uiwjs.github.io/uiw-admin/zip/\x1b[0m
41 | `;
42 |
43 | export const helpCli: string = `
44 | Usage: create-uiw-admin [options] [--help|h]
45 |
46 | Options:
47 |
48 | --version, -v Show version number
49 | --help, -h Displays help information.
50 | --output, -o Output directory.
51 | --example, -e Example from: \x1b[34mhttps://uiwjs.github.io/uiw-admin/zip/\x1b[0m, default: "uiw-admin-ts"
52 | --path, -p Specify the download target git address.
53 | default: "\x1b[34mhttps://uiwjs.github.io/uiw-admin/zip/\x1b[0m"
54 |
55 | ${helpExample}
56 |
57 | Copyright 2022
58 |
59 | `;
60 |
--------------------------------------------------------------------------------
/create-uiw-admin/test/cli.test.ts:
--------------------------------------------------------------------------------
1 | /** @jest-environment node */
2 | import fs from 'fs-extra';
3 | import path from 'path';
4 | import pkg from '../package.json';
5 | import { helpCli, run, helpExample } from '../src/utils';
6 |
7 | it('help test case.', async () => {
8 | expect(typeof helpExample).toEqual('string');
9 | expect(typeof helpCli).toEqual('string');
10 | });
11 |
12 | it('help test case.', async () => {
13 | const mockExit = jest.spyOn(console, 'log').mockImplementation();
14 | process.argv = process.argv.slice(0, 2);
15 | process.argv.push('my-app3');
16 | process.argv.push('--help');
17 | await import('../src/cli');
18 | expect(mockExit).toHaveBeenCalledWith(helpCli);
19 | mockExit.mockRestore();
20 | mockExit.mockClear();
21 | mockExit.mockReset();
22 | });
23 |
24 | it('version test case.', async () => {
25 | const mockExit = jest.spyOn(console, 'log').mockImplementation();
26 | process.argv = process.argv.slice(0, 2);
27 | process.argv.push('my-app4');
28 | process.argv.push('--version');
29 | await run();
30 | // @ts-ignore
31 | expect(mockExit).toHaveBeenCalledWith(
32 | `\n create-uiw-admin v${pkg.version}\n`,
33 | );
34 | mockExit.mockRestore();
35 | mockExit.mockClear();
36 | mockExit.mockReset();
37 | });
38 |
39 | it('create project. 1', async () => {
40 | console.log = jest.fn();
41 | process.argv = process.argv.slice(0, 2);
42 | process.argv.push('my-app2');
43 | process.argv.push('-f');
44 | process.argv.push('--output');
45 | process.argv.push('test');
46 | await run();
47 | expect(await fs.existsSync(path.resolve(__dirname, 'my-app2'))).toBeTruthy();
48 | await fs.remove('test/my-app2');
49 | }, 10000);
50 |
--------------------------------------------------------------------------------
/create-uiw-admin/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "esModuleInterop": true,
5 | "declaration": true,
6 | "target": "es2017",
7 | "noImplicitAny": true,
8 | "resolveJsonModule": true,
9 | "moduleResolution": "node",
10 | "emitDecoratorMetadata": true,
11 | "experimentalDecorators": true,
12 | "sourceMap": true,
13 | "strict": false,
14 | "skipLibCheck": true,
15 | "outDir": "lib",
16 | "baseUrl": "."
17 | },
18 | "include": ["src/**/*"]
19 | }
20 |
--------------------------------------------------------------------------------
/eslint-packages/config/README.md:
--------------------------------------------------------------------------------
1 | # eslint config
2 |
3 | uiw-admin 内置 eslint 规则配置
4 |
5 |
6 | ## 安装
7 |
8 | ```bash
9 | npm i eslint-config-uiw-admin -D # yarn add eslint-config-uiw-admin -D
10 | ```
11 |
12 | ## 用法
13 |
14 | 1. 第一种:项目的根文件夹中创建一个名为`.eslintrc.json`以下内容的文件:
15 |
16 | ```js
17 | module.exports ={
18 | // ...
19 | "extends": "uiw-admin"
20 | }
21 | ```
22 |
23 |
24 | 2. 第二种:项目的`package.json`加入以下内容
25 |
26 | ```json
27 | // ...
28 | "eslintConfig": {
29 | "extends": [
30 | "uiw-admin"
31 | ]
32 | }
33 | // ...
34 | ```
35 |
36 | > React17以上的版本配合babel可以单独使用 JSX 而无需引入 React
37 | > https://zh-hans.reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html
38 |
39 | ## 移除未使用的 React 引入
40 |
41 | ```
42 | cd your_project
43 | npx react-codemod update-react-imports
44 |
45 | ```
46 |
47 | 如果使用ts修改tsconfig.json文件
48 |
49 | ```json
50 | "jsx": "react-jsx",
51 | ```
52 |
53 |
54 | `eslint-config-uiw-admin` 您可以通过编辑`.eslintrc.json`文件来覆盖设置。在 [ESLint](https://eslint.org/docs/user-guide/configuring) 网站上了解更多关于配置 ESLint的信息。
55 |
56 | ## 默认规则
57 |
58 | - [no-const-assign](https://eslint.org/docs/rules/no-const-assign#no-const-assign): 'error',
59 | - [eqeqeq](https://eslint.org/docs/rules/eqeqeq#eqeqeq): 'error',
60 | - [max-lines](https://eslint.org/docs/rules/max-lines#max-lines): ['error', { max: 500 }],
61 | - [max-depth](https://eslint.org/docs/rules/max-depth#max-depth): ['error', 4],
62 | - [no-empty-function](https://eslint.org/docs/rules/no-empty-function#no-empty-function): 'error',
63 | - [no-empty](https://eslint.org/docs/rules/no-empty#no-empty): 'error',
64 | - [no-var](https://eslint.org/docs/rules/no-var#no-var): 'error',
65 | - [no-use-before-define](https://eslint.org/docs/rules/no-use-before-define#no-use-before-define): 'off',
66 | - [@typescript-eslint/no-use-before-define](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/src/rules/no-use-before-define.ts): ['error']
--------------------------------------------------------------------------------
/eslint-packages/config/index.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const path = require('path');
3 | const isTsProject = fs.existsSync(path.join(process.cwd(), './tsconfig.json'));
4 |
5 | const isJsMoreTs = async (path = 'src') => {
6 | const fg = require('fast-glob');
7 | const jsFiles = await fg(`${path}/src/**/*.{js,jsx}`, { deep: 3 });
8 | const tsFiles = await fg(`${path}/src/**/*.{ts,tsx}`, { deep: 3 });
9 | return jsFiles.length > tsFiles.length;
10 | };
11 |
12 | if (isTsProject) {
13 | try {
14 | isJsMoreTs(process.cwd()).then((jsMoreTs) => {
15 | if (!jsMoreTs) return;
16 | console.log('这是一个 TypeScript 项目,如果不是请删除 tsconfig.json');
17 | });
18 | } catch (e) {
19 | console.log(e);
20 | }
21 | }
22 |
23 | module.exports = {
24 | env: {
25 | browser: true,
26 | es2021: true,
27 | node: true,
28 | jest: true,
29 | },
30 | extends: ['react-app', 'plugin:react/jsx-runtime'],
31 | parser: '@typescript-eslint/parser',
32 | parserOptions: {
33 | ecmaFeatures: {
34 | jsx: true,
35 | },
36 | ecmaVersion: 12,
37 | sourceType: 'module',
38 | },
39 | plugins: ['react', '@typescript-eslint'],
40 | rules: {
41 | 'no-const-assign': 'error',
42 | eqeqeq: 'error',
43 | 'max-lines': ['error', { max: 500 }],
44 | 'max-depth': ['error', 4],
45 | 'no-empty-function': 'error',
46 | 'no-empty': 'error',
47 | 'no-var': 'error',
48 | 'no-use-before-define': 'off',
49 | 'react/jsx-uses-react': 'off',
50 | 'react/react-in-jsx-scope': 'off',
51 |
52 | // '@typescript-eslint/no-use-before-define': ['error'],
53 | },
54 | };
55 |
--------------------------------------------------------------------------------
/eslint-packages/config/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "eslint-config-uiw-admin",
3 | "version": "6.1.9",
4 | "description": "eslint 配置",
5 | "author": "Kenny Wong ",
6 | "homepage": "https://github.com/uiwjs/uiw-admin/tree/master/eslint-packages/config#readme",
7 | "main": "index.js",
8 | "license": "MIT",
9 | "files": [
10 | "index.js"
11 | ],
12 | "peerDependencies": {
13 | "eslint": ">=7.32.0",
14 | "eslint-plugin-import": "^2.26.0",
15 | "eslint-plugin-react": "^7.30.1"
16 | },
17 | "devDependencies": {
18 | "eslint-config-standard": "16.0.3",
19 | "eslint-plugin-node": "11.1.0",
20 | "eslint-plugin-promise": "6.0.0"
21 | },
22 | "publishConfig": {
23 | "access": "public"
24 | },
25 | "repository": {
26 | "type": "git",
27 | "url": "git+https://github.com/uiwjs/uiw-admin.git"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/examples/base/.editorconfig:
--------------------------------------------------------------------------------
1 | # http://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | charset = utf-8
9 | trim_trailing_whitespace = true
10 | insert_final_newline = true
11 |
12 | [*.md]
13 | trim_trailing_whitespace = false
14 |
15 | [Makefile]
16 | indent_style = tab
17 |
--------------------------------------------------------------------------------
/examples/base/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | lib
3 | build
4 | npm-debug.log*
5 | package-lock.json
6 | .eslintcache
7 | .DS_Store
8 | .cache
9 | .rdoc-dist
10 | .vscode
11 |
12 | *.bak
13 | *.tem
14 | *.temp
15 | #.swp
16 | *.*~
17 | ~*.*
18 | .uiw
19 | .idea
20 | .kktp
--------------------------------------------------------------------------------
/examples/base/.prettierignore:
--------------------------------------------------------------------------------
1 | **/*.md
2 | **/*.svg
3 | package.json
4 |
--------------------------------------------------------------------------------
/examples/base/.prettierrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | tabWidth: 2,
3 | bracketSameLine: true,
4 | arrowParens: 'always',
5 | singleQuote: true,
6 | semi: false, // 行位是否使用分号,默认为true
7 | bracketSpacing: true, // 对象大括号直接是否有空格,默认为true,效果:{ foo: bar }
8 | }
9 |
--------------------------------------------------------------------------------
/examples/base/.stackblitzrc:
--------------------------------------------------------------------------------
1 | {
2 | "installDependencies": true,
3 | "startCommand": "npm start",
4 | "installOptions": {
5 | "frozen-lockfile": true,
6 | "no-optional": true
7 | },
8 | "node": "16",
9 | "env": {
10 | "NODE_ENV": "development"
11 | }
12 | }
--------------------------------------------------------------------------------
/examples/base/README.md:
--------------------------------------------------------------------------------
1 | uiw-admin Example
2 | ===
3 |
4 | ## Open in CodeSandbox
5 |
6 | [](https://codesandbox.io/s/github/uiwjs/uiw-admin/tree/master/examples/base)
7 |
8 | ## Quick Start
9 |
10 | **development**
11 |
12 | Runs the project in development mode.
13 |
14 | ```bash
15 | npm install
16 | npm start
17 | ```
18 |
19 | ## 目录结构
20 | ```
21 | .
22 | ├── README.md
23 | ├── config
24 | │ └── routes.json 路由配置
25 | ├── mocker mock 数据
26 | │ ├── auth
27 | │ │ └── index.js
28 | │ ├── demo.js
29 | │ ├── index.js
30 | │ ├── login.js
31 | │ └── selectPage.js
32 | ├── package.json
33 | ├── public
34 | │ ├── favicon.ico
35 | │ └── index.html
36 | ├── sandbox.config.json
37 | ├── src
38 | │ ├── assets
39 | │ │ ├── head.png
40 | │ │ ├── logo-dark.svg
41 | │ │ └── logo-light.svg
42 | │ ├── index.css
43 | │ ├── index.tsx
44 | │ ├── layouts 框架组件
45 | │ │ ├── BasicLayout.tsx
46 | │ │ ├── UserLayout.tsx
47 | │ │ └── logo.svg
48 | │ ├── models remach models
49 | │ │ ├── Doc
50 | │ │ │ └── doc.ts
51 | │ │ ├── demo.ts
52 | │ │ ├── global.ts
53 | │ │ ├── home.ts
54 | │ │ └── login.ts
55 | │ ├── pages 页面, 文件名大写
56 | │ │ ├── Dashboard
57 | │ │ │ └── index.tsx
58 | │ │ ├── Demo
59 | │ │ │ ├── Detail
60 | │ │ │ │ ├── index.tsx
61 | │ │ │ │ └── items.tsx
62 | │ │ │ └── index.tsx
63 | │ │ ├── TableList
64 | │ │ │ └── index.tsx
65 | │ │ └── login
66 | │ │ ├── index.module.less
67 | │ │ └── index.tsx
68 | │ ├── react-app-env.d.ts
69 | │ └── servers 放置api文件的地方,文件名已后端接口模块名命名,不以路由命名
70 | │ └── index.ts
71 | └── tsconfig.json
72 | ```
--------------------------------------------------------------------------------
/examples/base/config/.kktprc.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | initEntery: true,
3 | initRoutes: {
4 | routesOutletElement: '@/routesOutletElement',
5 | },
6 | initModel: true,
7 | queryClient: true,
8 | define: {
9 | AUTH: false,
10 | STORAGE: 'local',
11 | SEARCH_MENU: true,
12 | BASE_NAME: '/uiw',
13 | TOKEN_NAME: 'aaa',
14 | TOKEN_STORAGE: 'bbb',
15 | },
16 | publicPath: './',
17 | }
18 |
--------------------------------------------------------------------------------
/examples/base/config/routes.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "path": "/login",
4 | "element": "@/layouts/UserLayout"
5 | },
6 | {
7 | "path": "/",
8 | "element": "@/layouts/BasicLayout",
9 | "children": [
10 | {
11 | "index": true,
12 | "redirect": "/home"
13 | },
14 | {
15 | "path": "/home",
16 | "name": "首页",
17 | "element": "@/pages/TableList",
18 | "icon": "home"
19 | },
20 | {
21 | "path": "/demo",
22 | "name": "列表查询/新增",
23 | "element": "@/pages/Demo",
24 | "icon": "home"
25 | },
26 | {
27 | "path": "/form",
28 | "name": "高级表单",
29 | "element": "@/pages/Form",
30 | "icon": "document"
31 | },
32 | {
33 | "path": "/:group/*",
34 | "name": "测试点击页面",
35 | "hideInMenu": true,
36 | "component": "@/pages/TableList",
37 | "icon": "home"
38 | },
39 | {
40 | "path": "/dom/exceptions",
41 | "name": "异常",
42 | "icon": "warning-o",
43 | "side": false,
44 | "children": [
45 | {
46 | "index": true,
47 | "redirect": "/dom/exceptions/403"
48 | },
49 | {
50 | "path": "/dom/exceptions/403",
51 | "name": "403",
52 | "element": "@uiw-admin/exceptions/esm/Exceptions/403"
53 | },
54 | {
55 | "path": "/dom/exceptions/500",
56 | "name": "500",
57 | "element": "@uiw-admin/exceptions/esm/Exceptions/500"
58 | },
59 | {
60 | "path": "/dom/exceptions/404",
61 | "name": "404",
62 | "element": "@uiw-admin/exceptions/esm/Exceptions/404"
63 | }
64 | ]
65 | }
66 | ]
67 | }
68 | ]
69 |
--------------------------------------------------------------------------------
/examples/base/mocker/auth/index.js:
--------------------------------------------------------------------------------
1 | module.exports.authList = [
2 | '/tableList',
3 | '/home',
4 | '/demo',
5 | '/dom',
6 | '/dom/*',
7 | '/tableList/:id',
8 | '/exceptions',
9 | '/exceptions/403',
10 | '/exceptions/404',
11 | '/exceptions/500',
12 | ]
13 |
--------------------------------------------------------------------------------
/examples/base/mocker/demo.js:
--------------------------------------------------------------------------------
1 | module.exports.insert = function (req, res) {
2 | return res.status(200).json({
3 | code: 200,
4 | message: '新增成功',
5 | data: {},
6 | })
7 | }
8 |
9 | module.exports.update = function (req, res) {
10 | return res.status(200).json({
11 | code: 200,
12 | message: '编辑成功',
13 | data: {},
14 | })
15 | }
16 |
17 | module.exports.selectById = function (req, res) {
18 | return res.status(200).json({
19 | code: 200,
20 | message: '获取详情成功',
21 | data: {
22 | input: 'Jason',
23 | textarea: '蟠龙路',
24 | select: 4,
25 | switch: true,
26 | radio: 'man',
27 | checkbox: ['sichuan', 'hubei'],
28 | dateInputsecond: '2021-1-21 23:59:59',
29 | dateInput: '2021-1-21',
30 | monthPicker: '2021-1',
31 | timePicker: '2021-1-21 23:59:59',
32 | slider: 90,
33 | upload: [
34 | {
35 | dataURL: 'https://avatars2.githubusercontent.com/u/1680273?s=40&v=4',
36 | name: 'uiw.png',
37 | },
38 | ],
39 | searchSelect: [1, 2],
40 | rate: 4,
41 | input2: '123456789',
42 | },
43 | })
44 | }
45 |
46 | module.exports.upload = function (req, res) {
47 | return res.status(200).json({
48 | code: 200,
49 | message: '获取详情成功',
50 | uid: '1234',
51 | })
52 | }
53 |
--------------------------------------------------------------------------------
/examples/base/mocker/index.js:
--------------------------------------------------------------------------------
1 | const { getData, getCity } = require('./selectPage')
2 | const { login, verify, logout, reloadAuth } = require('./login')
3 | const { insert, update, selectById, upload } = require('./demo')
4 |
5 | const proxy = {
6 | 'GET /api/user': { id: 1, username: 'kenny', sex: 6 },
7 | 'POST /api/user': { id: 1, username: 'kenny', sex: 6 },
8 | 'POST /api/login': login,
9 | 'POST /api/logout': logout,
10 | 'GET /api/user/verify': verify,
11 | 'GET /api/city': getCity,
12 | 'POST /api/getData': getData,
13 | 'POST /api/reloadAuth': reloadAuth,
14 | 'POST /api/demo/selectById': selectById,
15 | 'POST /api/demo/insert': insert,
16 | 'POST /api/demo/update': update,
17 | 'POST /api/demo/upload': upload,
18 | }
19 |
20 | module.exports = proxy
21 |
--------------------------------------------------------------------------------
/examples/base/mocker/login.js:
--------------------------------------------------------------------------------
1 | const { authList } = require('./auth')
2 |
3 | let token = ''
4 |
5 | module.exports.login = function (req, res) {
6 | const { password, username } = req.body
7 | if (password === 'admin' && username === 'admin') {
8 | token = '5c2d6d45-ec94-319c-a9c8-cae43e192b65'
9 | return res.json({
10 | updated_at: '2018/09/23 15:59:52',
11 | created_at: '2018/09/23 15:59:52',
12 | id: 1,
13 | username: 'admin',
14 | name: 'admin',
15 | admin: true,
16 | bio: '',
17 | location: '',
18 | organization: '',
19 | preferred_language: '',
20 | email: 'admin@admin.com',
21 | public_email: null,
22 | avatar: '',
23 | linkedin: '',
24 | web_url: null,
25 | skype: '',
26 | state: 'active',
27 | token: '5c2d6d45-ec94-319c-a9c8-cae43e192b65',
28 | authList: authList || [],
29 | })
30 | }
31 | return res.status(401).json({
32 | code: 401,
33 | error: '用户名或密码错误!',
34 | })
35 | }
36 |
37 | module.exports.reloadAuth = function (req, res) {
38 | return res.json({
39 | code: 200,
40 | token: '5c2d6d45-ec94-319c-a9c8-cae43e192b65',
41 | authList: authList || [],
42 | })
43 | }
44 |
45 | module.exports.verify = function (req, res) {
46 | if (!token) {
47 | return res.status(401).json({
48 | code: 401,
49 | error: '用户未登录!',
50 | })
51 | }
52 | return res.json({
53 | updated_at: '2018/09/23 15:59:52',
54 | created_at: '2018/09/23 15:59:52',
55 | id: 1,
56 | username: 'admin',
57 | name: 'admin',
58 | admin: true,
59 | bio: '',
60 | location: '',
61 | organization: '',
62 | preferred_language: '',
63 | email: 'admin@admin.com',
64 | public_email: null,
65 | avatar: '',
66 | linkedin: '',
67 | web_url: null,
68 | skype: '',
69 | state: 'active',
70 | token: token,
71 | authList: authList || [],
72 | })
73 | }
74 |
75 | module.exports.logout = function (req, res) {
76 | token = ''
77 | return res.status(200).json({
78 | message: '退出登录!',
79 | })
80 | }
81 |
82 | module.exports.refesh = function (req, res) {
83 | return res.status(200).json({
84 | code: 200,
85 | message: '刷新权限成功',
86 | data: {
87 | authList: authList || [],
88 | },
89 | })
90 | }
91 |
--------------------------------------------------------------------------------
/examples/base/mocker/selectPage.js:
--------------------------------------------------------------------------------
1 | module.exports.getData = function (req, res) {
2 | const { page, pageSize } = req.body
3 | setTimeout(() => {
4 | return res.status(200).json({
5 | code: 1,
6 | total: 30,
7 | page: page,
8 | pageSize: pageSize,
9 | data: [
10 | {
11 | name: '邓紫棋',
12 | age: page,
13 | info: '又名G.E.M.,原名邓诗颖,1991年8月16日生于中国上海,中国香港创作型女歌手。',
14 | },
15 | {
16 | name: '李易峰',
17 | age: page,
18 | info: '1987年5月4日出生于四川成都,中国内地男演员、流行乐歌手、影视制片人',
19 | },
20 | {
21 | name: '范冰冰',
22 | age: page,
23 | info: '1981年9月16日出生于山东青岛,中国影视女演员、制片人、流行乐女歌手',
24 | },
25 | {
26 | name: '杨幂',
27 | age: page,
28 | info: '1986年9月12日出生于北京市,中国内地影视女演员、流行乐歌手、影视制片人。',
29 | },
30 | {
31 | name: 'Angelababy',
32 | age: page,
33 | info: '1989年2月28日出生于上海市,华语影视女演员、时尚模特。',
34 | },
35 | {
36 | name: '唐嫣',
37 | age: page,
38 | info: '1983年12月6日出生于上海市,毕业于中央戏剧学院表演系本科班',
39 | },
40 | {
41 | name: '吴亦凡',
42 | age: page,
43 | info: '1990年11月06日出生于广东省广州市,华语影视男演员、流行乐歌手。',
44 | },
45 | ],
46 | })
47 | }, 1000)
48 | }
49 |
50 | module.exports.getCity = function (req, res) {
51 | const search = req.query.val
52 | ? [{ label: req.query.val, val: req.query.val }]
53 | : []
54 | setTimeout(() => {
55 | return res.status(200).json({
56 | code: 1,
57 | data: [
58 | {
59 | label: '南通',
60 | value: '南通',
61 | },
62 | {
63 | label: '通州',
64 | value: '通州',
65 | },
66 | ].concat(search),
67 | })
68 | }, 1000)
69 | }
70 |
--------------------------------------------------------------------------------
/examples/base/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@examples/base",
3 | "version": "6.1.9",
4 | "description": "Use Rematch & TypeScript for the project.",
5 | "private": true,
6 | "scripts": {
7 | "start": "kktp start",
8 | "build": "kktp build",
9 | "doc": "kktp doc --entry=./build --local",
10 | "test": "kktp test --env=jsdom",
11 | "coverage": "kktp test --env=jsdom --coverage"
12 | },
13 | "repository": {
14 | "type": "git",
15 | "url": "https://github.com/uiwjs/uiw-admin.git"
16 | },
17 | "keywords": [],
18 | "author": "",
19 | "license": "MIT",
20 | "peerDependencies": {
21 | "@babel/runtime": ">=7.21.0",
22 | "@swc-node/core": ">=1.10.1",
23 | "@swc-node/register": ">=1.6.1",
24 | "@swc/core": ">=1.3.55"
25 | },
26 | "dependencies": {
27 | "@kkt/pro": "^1.0.14",
28 | "@uiw-admin/authorized": "6.1.9",
29 | "@uiw-admin/basic-layouts": "6.1.9",
30 | "@uiw-admin/components": "6.1.9",
31 | "@uiw-admin/config": "6.1.9",
32 | "@uiw-admin/document-title": "6.1.9",
33 | "@uiw-admin/exceptions": "6.1.9",
34 | "@uiw-admin/layout-tabs": "6.1.9",
35 | "@uiw-admin/user-login": "6.1.9",
36 | "@uiw-admin/utils": "6.1.9",
37 | "@uiw/reset.css": "~1.0.5",
38 | "axios": "^0.27.0",
39 | "classnames": "~2.3.1",
40 | "styled-components": "^5.3.5",
41 | "uiw": "^4.21.26"
42 | },
43 | "devDependencies": {
44 | "lint-staged": "~12.5.0",
45 | "pirates": "~4.0.5",
46 | "prettier": "^2.7.0",
47 | "yorkie": "~2.0.0"
48 | },
49 | "lint-staged": {
50 | "*.{js,jsx,ts,tsx}": [
51 | "eslint --fix"
52 | ],
53 | "*.{js,jsx,ts,tsx,less,md,json}": [
54 | "prettier --write"
55 | ]
56 | },
57 | "gitHooks": {
58 | "pre-commit": "lint-staged"
59 | },
60 | "eslintConfig": {
61 | "extends": [
62 | "react-app",
63 | "react-app/jest",
64 | "uiw-admin"
65 | ]
66 | },
67 | "browserslist": {
68 | "production": [
69 | ">0.2%",
70 | "not dead",
71 | "not op_mini all"
72 | ],
73 | "development": [
74 | "last 1 chrome version",
75 | "last 1 firefox version",
76 | "last 1 safari version"
77 | ]
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/examples/base/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uiwjs/uiw-admin/f4abb975dd6a203b5755df1b5e025596204d9186/examples/base/public/favicon.ico
--------------------------------------------------------------------------------
/examples/base/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | uiw admin
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/examples/base/sandbox.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "template": "node",
3 | "container": {
4 | "node": "16"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/examples/base/src/assets/head.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uiwjs/uiw-admin/f4abb975dd6a203b5755df1b5e025596204d9186/examples/base/src/assets/head.png
--------------------------------------------------------------------------------
/examples/base/src/assets/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | export const chat = (
3 |
9 | )
10 |
--------------------------------------------------------------------------------
/examples/base/src/assets/logo-dark.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/examples/base/src/assets/logo-light.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/examples/base/src/layouts/BasicLayout.tsx:
--------------------------------------------------------------------------------
1 | import { Badge, Icon } from 'uiw'
2 | import AuthPage from '@uiw-admin/authorized'
3 | import { KktproPageProps, useReactMutation } from '@kkt/pro'
4 | import BasicLayout, {
5 | useLayouts,
6 | BasicLayoutProps,
7 | } from '@uiw-admin/basic-layouts'
8 | import LayoutsTabs from '@uiw-admin/layout-tabs'
9 |
10 | function BasicLayoutScreen(props: KktproPageProps) {
11 | const { navigate, routes = [] } = props
12 |
13 | const layouts = useLayouts()
14 |
15 | const { mutate } = useReactMutation({
16 | url: '/api/reloadAuth',
17 | method: 'POST',
18 | onSuccess: (data: any) => {
19 | if (data && data.code === 200) {
20 | sessionStorage.setItem('token', data.token)
21 | sessionStorage.setItem('auth', JSON.stringify(data.authList || []))
22 | localStorage.setItem('token', data.token)
23 | localStorage.setItem('auth', JSON.stringify(data.authList || []))
24 | // window.location.reload()
25 | layouts.closeMenu()
26 | }
27 | },
28 | })
29 |
30 | const basicLayoutProps: BasicLayoutProps = {
31 | onReloadAuth: () => mutate(),
32 | // 修改密码以及其他操作在项目中进行
33 | menus: [
34 | {
35 | title: '欢迎来到uiw',
36 | icon: ,
37 | onClick: () => layouts.closeMenu(),
38 | },
39 | {
40 | title: '修改密码',
41 | icon: ,
42 | onClick: () => layouts.closeMenu(),
43 | },
44 | ],
45 | profile: {
46 | avatar: require('../assets/head.png'),
47 | menuLeft: (
48 |
49 |
50 |
55 |
56 |
57 | ),
58 | },
59 | layouts,
60 | routes: routes,
61 | headerLayout: 'top',
62 | headerBackground: '#343a40',
63 | headerFontColor: '#fff',
64 | }
65 |
66 | return (
67 |
68 | {
72 | navigate('/')
73 | }}>
74 |
75 | {/* */}
76 |
77 |
78 | )
79 | }
80 | export default BasicLayoutScreen
81 |
--------------------------------------------------------------------------------
/examples/base/src/layouts/UserLayout.tsx:
--------------------------------------------------------------------------------
1 | import UserLogin from '@uiw-admin/user-login'
2 | import { setCookie } from '@uiw-admin/utils'
3 | import { Notify } from 'uiw'
4 | import { KktproPageProps } from '@kkt/pro'
5 |
6 | const UserLayout = (props: KktproPageProps) => {
7 | const { navigate } = props
8 |
9 | return (
10 | ({ a: 12, b: 1221, ...store })}
28 | onSuccess={(data) => {
29 | if (data && data.token) {
30 | setCookie('token', data.token)
31 | sessionStorage.setItem('token', data.token)
32 | sessionStorage.setItem('auth', JSON.stringify(data.authList || []))
33 | localStorage.setItem('token', data.token)
34 | localStorage.setItem('auth', JSON.stringify(data.authList || []))
35 | navigate?.('/home', { replace: true })
36 | } else {
37 | Notify.error({
38 | title: '错误通知',
39 | description: data.error || '请求失败',
40 | })
41 | }
42 | }}
43 | />
44 | )
45 | }
46 | export default UserLayout
47 |
--------------------------------------------------------------------------------
/examples/base/src/layouts/logo.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/examples/base/src/models/Doc/doc.ts:
--------------------------------------------------------------------------------
1 | import { Dispatch } from '@kkt/pro'
2 |
3 | export interface GlobalState {
4 | test: string
5 | [s: string]: any
6 | }
7 |
8 | const doc = {
9 | name: 'doc',
10 | state: {
11 | test: 'doc model',
12 | },
13 | reducers: {
14 | updateState: (state: GlobalState, payload: GlobalState) => ({
15 | ...state,
16 | ...payload,
17 | }),
18 | },
19 | effects: (dispatch: Dispatch) => ({
20 | async verify() {
21 | const dph = dispatch
22 | dph.doc.updateState({ test: '测试2' })
23 | },
24 | }),
25 | }
26 |
27 | export default doc
28 |
--------------------------------------------------------------------------------
/examples/base/src/models/demo.ts:
--------------------------------------------------------------------------------
1 | import { selectById } from '../servers/demo'
2 |
3 | const demo = {
4 | name: 'demo',
5 | state: {
6 | drawerVisible: false,
7 | tableType: '',
8 | queryInfo: {},
9 | isView: false,
10 | a: 1,
11 | },
12 | reducers: {
13 | updateState: (state: any, payload: any) => ({
14 | ...state,
15 | ...payload,
16 | }),
17 | },
18 | effects: (dispatch: any) => ({
19 | async selectById(payload: any) {
20 | const dph = dispatch
21 | const data = await selectById(payload)
22 | if (data.code === 200) {
23 | dph.demo.updateState({
24 | drawerVisible: true,
25 | queryInfo: data.data || {},
26 | })
27 | }
28 | },
29 | clean() {
30 | const dph = dispatch
31 | dph.demo.updateState({
32 | drawerVisible: false,
33 | tableType: '',
34 | queryInfo: {},
35 | isView: false,
36 | })
37 | },
38 | }),
39 | }
40 | export default demo
41 |
--------------------------------------------------------------------------------
/examples/base/src/models/global.ts:
--------------------------------------------------------------------------------
1 | import { Dispatch } from '@kkt/pro'
2 | export interface GlobalState {
3 | test: string
4 | [s: string]: any
5 | }
6 |
7 | const global = {
8 | name: 'global',
9 | state: {
10 | test: '测试全局State',
11 | },
12 | reducers: {
13 | updateState: (state: GlobalState, payload: GlobalState) => ({
14 | ...state,
15 | ...payload,
16 | }),
17 | },
18 | effects: (dispatch: Dispatch) => ({
19 | async verify() {
20 | const dph = dispatch
21 | dph.global.updateState({ test: '测试2' })
22 | },
23 | }),
24 | }
25 |
26 | export default global
27 |
--------------------------------------------------------------------------------
/examples/base/src/models/home.ts:
--------------------------------------------------------------------------------
1 | import { Dispatch } from '@kkt/pro'
2 |
3 | export interface GlobalState {
4 | test: string
5 | [s: string]: any
6 | }
7 |
8 | const home = {
9 | name: 'home',
10 | state: {
11 | test: 'home',
12 | },
13 | reducers: {
14 | updateState: (state: GlobalState, payload: GlobalState) => ({
15 | ...state,
16 | ...payload,
17 | }),
18 | },
19 | effects: (dispatch: any) => ({
20 | async verify() {
21 | const dph = dispatch as Dispatch
22 | dph.global.updateState({ test: 'homg2323' })
23 | },
24 | }),
25 | }
26 |
27 | export default home
28 |
--------------------------------------------------------------------------------
/examples/base/src/models/login.ts:
--------------------------------------------------------------------------------
1 | // import { Dispatch } from '@kkt/pro';
2 |
3 | export interface LoginState {
4 | token?: string | null
5 | userData?: {
6 | username: string
7 | } | null
8 | }
9 |
10 | const login = {
11 | name: 'login',
12 | state: {
13 | userData: null,
14 | token: null,
15 | },
16 | reducers: {
17 | updateState: (state: any, payload: LoginState) => ({
18 | ...state,
19 | ...payload,
20 | }),
21 | },
22 | effects: (dispatch: any) => ({
23 | async submit() {
24 | // console.log(555, dispatch.login, data)
25 | // dispatch.login.updateState({ token: '测试2' })
26 | // sessionStorage.setItem('auth', JSON.stringify(['/home', '/dac']))
27 | // history.push('/home')
28 | // this.updateState()
29 | // await login({ username: 'test', password: 'www' });
30 | // dispatch.sharks.increment(payload)
31 | // `dispatch.s` will suggest `sharks`
32 | },
33 | }),
34 | }
35 |
36 | export default login
37 |
--------------------------------------------------------------------------------
/examples/base/src/pages/Dashboard/index.tsx:
--------------------------------------------------------------------------------
1 | import { KktproPageProps } from '@kkt/pro'
2 | import { Form } from '@uiw-admin/components'
3 | import { Input } from 'uiw'
4 |
5 | const Dashboard = (props: KktproPageProps) => {
6 | return (
7 |
8 | ,
13 | rules: [
14 | {
15 | required: true,
16 | message: '必填',
17 | },
18 | () => {
19 | return '222'
20 | },
21 | ],
22 | },
23 | }}
24 | />
25 | Dashboard
26 |
27 |
28 |
29 |
30 |
31 |
32 | )
33 | }
34 | export default Dashboard
35 |
--------------------------------------------------------------------------------
/examples/base/src/pages/Dashboard/models/index.ts:
--------------------------------------------------------------------------------
1 | import { Dispatch, RootModel } from '@kkt/pro'
2 | import { createModel } from '@rematch/core'
3 |
4 | export interface GlobalState {
5 | test: string
6 | [s: string]: any
7 | }
8 |
9 | const doc = createModel()({
10 | name: 'docDs',
11 | state: {
12 | test: 'doc model',
13 | },
14 | reducers: {
15 | updateState: (state: GlobalState, payload: GlobalState) => ({
16 | ...state,
17 | ...payload,
18 | }),
19 | },
20 | effects: (dispatch) => ({
21 | async verify() {
22 | const dph = dispatch as Dispatch
23 | dph.doc.updateState({ test: '测试2' })
24 | },
25 | }),
26 | })
27 |
28 | export default doc
29 |
--------------------------------------------------------------------------------
/examples/base/src/pages/Demo/models/index.ts:
--------------------------------------------------------------------------------
1 | import { Dispatch } from '@kkt/pro'
2 |
3 | export interface GlobalState {
4 | test: string
5 | [s: string]: any
6 | }
7 |
8 | const doc = {
9 | name: 'docD',
10 | state: {
11 | test: 'doc model',
12 | },
13 | reducers: {
14 | updateState: (state: GlobalState, payload: GlobalState) => ({
15 | ...state,
16 | ...payload,
17 | }),
18 | },
19 | effects: (dispatch: any) => ({
20 | async verify() {
21 | const dph = dispatch as Dispatch
22 | dph.doc.updateState({ test: '测试2' })
23 | },
24 | }),
25 | }
26 |
27 | export default doc
28 |
--------------------------------------------------------------------------------
/examples/base/src/pages/Form/index.less:
--------------------------------------------------------------------------------
1 | .fiexd-btns {
2 | position: sticky;
3 | bottom: 0;
4 | background: #fff;
5 | z-index: 9;
6 | padding: 10px;
7 | margin-top: 14px;
8 | display: flex;
9 | justify-content: center;
10 | align-items: center;
11 | .btn {
12 | width: 120px;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/examples/base/src/pages/Form/models/index.ts:
--------------------------------------------------------------------------------
1 | import { Dispatch } from '@kkt/pro'
2 |
3 | export interface GlobalState {
4 | test: string
5 | [s: string]: any
6 | }
7 |
8 | const doc = {
9 | name: 'form',
10 | state: {
11 | test: 'doc model',
12 | },
13 | reducers: {
14 | updateState: (state: GlobalState, payload: GlobalState) => ({
15 | ...state,
16 | ...payload,
17 | }),
18 | },
19 | effects: (dispatch: any) => ({
20 | async verify() {
21 | const dph = dispatch as Dispatch
22 | dph.doc.updateState({ test: '测试2' })
23 | },
24 | }),
25 | }
26 |
27 | export default doc
28 |
--------------------------------------------------------------------------------
/examples/base/src/pages/ceshi.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | const App = () => {
4 | return 234
5 | }
6 |
7 | export default App
8 |
--------------------------------------------------------------------------------
/examples/base/src/react-app-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | declare module '*.module.less' {
4 | const classes: { readonly [key: string]: string }
5 | export default classes
6 | }
7 |
--------------------------------------------------------------------------------
/examples/base/src/routesOutletElement/index.css:
--------------------------------------------------------------------------------
1 | #root, body, html {
2 | height: 100%;
3 | }
--------------------------------------------------------------------------------
/examples/base/src/routesOutletElement/index.tsx:
--------------------------------------------------------------------------------
1 | import { cloneElement } from 'react'
2 | import { KktproRoutesProps } from '@kkt/pro'
3 | import '@uiw/reset.css'
4 | import './index.css'
5 |
6 | interface RoutesOutletElementProps {
7 | children: React.ReactNode
8 | routes: KktproRoutesProps[]
9 | }
10 | const RoutesOutletElement = (props: RoutesOutletElementProps) => {
11 | const { routes } = props
12 |
13 | return cloneElement(props.children as JSX.Element, {
14 | router: routes,
15 | })
16 | }
17 | export default RoutesOutletElement
18 |
--------------------------------------------------------------------------------
/examples/base/src/servers/demo.ts:
--------------------------------------------------------------------------------
1 | import { request } from '@uiw-admin/utils'
2 |
3 | function selectById(params: { id: string }) {
4 | return request('/api/demo/selectById', {
5 | method: 'POST',
6 | body: { ...params },
7 | })
8 | }
9 |
10 | export { selectById }
11 |
--------------------------------------------------------------------------------
/examples/base/src/servers/index.ts:
--------------------------------------------------------------------------------
1 | import useSWR from 'swr'
2 |
3 | // 公共接口数据 重复数据hooks 都建在此文件夹
4 | // 利用swr复用接口数据,各个页面都可用
5 | // https://swr.vercel.app/zh-CN/docs/getting-started#%E5%8F%AF%E5%A4%8D%E7%94%A8%E7%BB%84%E4%BB%B6
6 |
7 | // 模糊获取城市接口
8 | function useCity(val: string) {
9 | const { data, error } = useSWR(`/api/city/?val=${val}`)
10 | return {
11 | city: data?.data,
12 | isLoading: !error && !data,
13 | isError: error,
14 | }
15 | }
16 |
17 | export { useCity }
18 |
--------------------------------------------------------------------------------
/examples/base/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "esnext",
4 | "lib": ["esnext", "dom"],
5 | "allowJs": true,
6 | "skipLibCheck": true,
7 | "esModuleInterop": true,
8 | "allowSyntheticDefaultImports": true,
9 | "strict": true,
10 | "forceConsistentCasingInFileNames": true,
11 | "module": "esnext",
12 | "moduleResolution": "node",
13 | "resolveJsonModule": true,
14 | "isolatedModules": true,
15 | "declaration": true,
16 | "baseUrl": ".",
17 | "jsx": "react-jsx",
18 | "noFallthroughCasesInSwitch": true,
19 | "noEmit": true,
20 | "paths": {
21 | "@/*": ["./src/*"],
22 | "@@/*": ["./src/.kktp/*"]
23 | }
24 | },
25 | "include": ["src/**/*", "config/.kktprc.ts"]
26 | }
27 |
--------------------------------------------------------------------------------
/examples/website/README.md:
--------------------------------------------------------------------------------
1 | website: https://uiwjs.github.io/uiw-admin
--------------------------------------------------------------------------------
/examples/website/config/.kktprc.ts:
--------------------------------------------------------------------------------
1 | import pkg from '../package.json';
2 | import { mdCodeModulesLoader } from 'markdown-react-code-preview-loader';
3 | import type { WebpackConfiguration, LoaderConfOptions } from 'kkt';
4 |
5 | export default {
6 | initEntery: true,
7 | initRoutes: true,
8 | initModel: true,
9 | define: {
10 | VERSION: pkg.version,
11 | AUTH: false,
12 | STORAGE: 'local',
13 | SEARCH_MENU: true,
14 | },
15 | publicPath: './',
16 | overrideWebpack: (
17 | conf: WebpackConfiguration,
18 | env: 'development' | 'production',
19 | options: LoaderConfOptions | undefined,
20 | ) => {
21 | conf.module!.exprContextCritical = false;
22 | conf.module!.exprContextRecursive = false;
23 | conf = mdCodeModulesLoader(conf);
24 | return conf;
25 | },
26 | };
27 |
--------------------------------------------------------------------------------
/examples/website/config/routes.js:
--------------------------------------------------------------------------------
1 | import { Navigate } from 'react-router-dom';
2 |
3 | const routeList = [
4 | {
5 | path: '/example',
6 | element: '@/pages/example',
7 | },
8 | {
9 | path: '/',
10 | element: '@/components/Layouts/index',
11 | children: [
12 | {
13 | index: true,
14 | redirect: '/home',
15 | },
16 | { path: '/home', element: '@/pages/home' },
17 | {
18 | path: '/docs',
19 | children: [
20 | {
21 | index: true,
22 | redirect: '/docs/quick-start',
23 | },
24 | { path: '/docs/quick-start/*', element: '@/pages/quick-start' },
25 | { path: '/docs/newPages/*', element: '@/pages/newPages' },
26 | { path: '/docs/mocker/*', element: '@/pages/mocker' },
27 | { path: '/docs/request/*', element: '@/pages/request' },
28 | { path: '/docs/models/*', element: '@/pages/models' },
29 | { path: '/docs/auth/*', element: '@/pages/auth' },
30 | { path: '/docs/proxy/*', element: '@/pages/proxy' },
31 | { path: '/docs/eslint-config/*', element: '@/pages/eslint-config' },
32 | ],
33 | },
34 | {
35 | path: '/components',
36 | children: [
37 | {
38 | index: true,
39 | redirect: '/components/authorized',
40 | },
41 | { path: '/components/authorized/*', element: '@/pages/authorized' },
42 | {
43 | path: '/components/basic-layouts/*',
44 | element: '@/pages/basic-layouts',
45 | },
46 | { path: '/components/config/*', element: '@/pages/config' },
47 | {
48 | path: '/components/document-title/*',
49 | element: '@/pages/document-title',
50 | },
51 | { path: '/components/exceptions/*', element: '@/pages/exceptions' },
52 | {
53 | name: '选项卡',
54 | path: '/components/layout-tabs/*',
55 | element: '@/pages/layout-tabs',
56 | },
57 | { path: '/components/plugins/*', element: '@/pages/plugins' },
58 | {
59 | name: '登录页',
60 | path: '/components/user-login/*',
61 | element: '@/pages/user-login',
62 | },
63 | { path: '/components/utils/*', element: '@/pages/utils' },
64 | { path: '/components/components/*', element: '@/pages/components' },
65 | {
66 | path: '/components/protable/*',
67 | element: '@/pages/components/Protable',
68 | },
69 | {
70 | path: '/components/prodrawer/*',
71 | element: '@/pages/components/ProDrawer',
72 | },
73 | {
74 | path: '/components/proform/*',
75 | element: '@/pages/components/ProForm',
76 | },
77 | {
78 | path: '/components/skeleton/*',
79 | element: '@/pages/components/Skeleton',
80 | },
81 | ],
82 | },
83 | { path: '*', element: '@uiw-admin/exceptions/esm/Exceptions/404' },
84 | ],
85 | },
86 | { path: '*', element: '@uiw-admin/exceptions/esm/Exceptions/404' },
87 | ];
88 |
89 | export default routeList;
90 |
--------------------------------------------------------------------------------
/examples/website/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "website",
3 | "version": "6.1.9",
4 | "private": true,
5 | "description": "new webiste with kktp.",
6 | "scripts": {
7 | "build": "kktp build",
8 | "start": "CI=false kktp start",
9 | "prettier": "prettier --write '**/*.{js,jsx,tsx,ts,less,md,json}'",
10 | "map": "source-map-explorer build/static/js/*.js --html build/website-result.html"
11 | },
12 | "license": "MIT",
13 | "peerDependencies": {
14 | "@babel/runtime": ">=7.12.0",
15 | "react": ">=16.14.0",
16 | "react-dom": ">=16.14.0"
17 | },
18 | "dependencies": {
19 | "@babel/plugin-proposal-private-property-in-object": "7.21.0",
20 | "@react-login-page/base": "^0.4.4",
21 | "@react-login-page/page1": "^0.4.4",
22 | "@react-login-page/page2": "^0.4.4",
23 | "@react-login-page/page3": "^0.4.4",
24 | "@react-login-page/page4": "^0.4.4",
25 | "@react-login-page/page5": "^0.4.4",
26 | "@react-login-page/page6": "^0.4.4",
27 | "@react-login-page/page7": "^0.4.4",
28 | "@types/styled-components": "^5.1.26",
29 | "@uiw-admin/authorized": "6.1.9",
30 | "@uiw-admin/basic-layouts": "6.1.9",
31 | "@uiw-admin/components": "6.1.9",
32 | "@uiw-admin/config": "6.1.9",
33 | "@uiw-admin/document-title": "6.1.9",
34 | "@uiw-admin/exceptions": "6.1.9",
35 | "@uiw-admin/layout-tabs": "6.1.9",
36 | "@uiw-admin/plugins": "6.1.9",
37 | "@uiw-admin/user-login": "6.1.9",
38 | "@uiw/react-back-to-top": "^1.2.1",
39 | "@uiw/react-code-preview": "4.0.5",
40 | "@uiw/react-domain-verify": "1.1.2",
41 | "@uiw/react-github-corners": "1.5.3",
42 | "@uiw/react-loader": "4.9.7",
43 | "@uiw/react-markdown-preview": "4.1.10",
44 | "@uiw/reset.css": "1.0.5",
45 | "@wcj/dark-mode": "^1.0.15",
46 | "markdown-react-code-preview-loader": "2.1.5",
47 | "react-code-preview-layout": "3.0.0",
48 | "react-login-page": "^0.4.4",
49 | "react-test-renderer": "17.0.2",
50 | "styled-components": "^5.3.5",
51 | "uiw": "^4.21.26"
52 | },
53 | "devDependencies": {
54 | "@kkt/pro": "^1.0.13",
55 | "@types/react-test-renderer": "17.0.1",
56 | "hast": "^1.0.0",
57 | "rehype-rewrite": "^3.0.6",
58 | "source-map-explorer": "~2.5.2"
59 | },
60 | "browserslist": {
61 | "production": [
62 | ">0.2%",
63 | "not dead",
64 | "not op_mini all"
65 | ],
66 | "development": [
67 | "last 1 chrome version",
68 | "last 1 firefox version",
69 | "last 1 safari version"
70 | ]
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/examples/website/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | uiw admin
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/examples/website/public/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/examples/website/src/components/Layouts/Menu/index.tsx:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from 'react';
2 | import { useLocation } from '@kkt/pro';
3 | import {
4 | MenusConfigObject,
5 | menusDocsConfig,
6 | menusComponentsConfig,
7 | } from '@/menus';
8 | import { Divider, MenuLabel, MenuA, Wrapper, MenuWrapper } from './style';
9 |
10 | export interface MenuData {
11 | divider?: boolean;
12 | path?: string;
13 | size?: string | 'small';
14 | name: string;
15 | }
16 |
17 | const getRouters = (data: MenusConfigObject[] = [], path: string = '') => {
18 | const result: React.ReactNode[] = [];
19 | data.forEach((item, idx) => {
20 | if (item.path) {
21 | if (item.target || /^https?:\/\//.test(path)) {
22 | result.push(
23 |
28 | {item.title}
29 | ,
30 | );
31 | } else {
32 | result.push(
33 |
38 | {item.title}
39 | ,
40 | );
41 | }
42 | } else {
43 | result.push(
44 | {item.title},
45 | );
46 | }
47 | });
48 | return result;
49 | };
50 |
51 | const Menu = () => {
52 | const { pathname } = useLocation();
53 | const [result, setResult] = useState();
54 | useEffect(() => {
55 | if (/docs/.test(pathname)) {
56 | setResult(getRouters(menusDocsConfig, pathname));
57 | }
58 | if (/components/.test(pathname)) {
59 | setResult(getRouters(menusComponentsConfig, pathname));
60 | }
61 | }, [pathname]);
62 |
63 | return (
64 |
65 | {result}
66 |
67 | );
68 | };
69 |
70 | export default Menu;
71 |
--------------------------------------------------------------------------------
/examples/website/src/components/Layouts/Menu/style.ts:
--------------------------------------------------------------------------------
1 | import styled from 'styled-components';
2 | import { NavLink } from '@kkt/pro';
3 |
4 | export const Wrapper = styled.div`
5 | position: fixed;
6 | top: 0;
7 | z-index: 2;
8 | width: 240px;
9 | height: 100%;
10 | padding-top: 58px;
11 | `;
12 |
13 | export const MenuWrapper = styled.div`
14 | overflow: auto;
15 | display: flex;
16 | padding: 10px 6px;
17 | flex-direction: column;
18 | gap: 6px;
19 | height: 100%;
20 | box-sizing: border-box;
21 | `;
22 |
23 | export const MenuLabel = styled(NavLink)`
24 | display: flex;
25 | text-decoration: none;
26 | justify-content: flex-start;
27 | align-items: stretch;
28 | padding: 5px 12px;
29 | border-radius: 4px;
30 | color: currentColor;
31 | margin-left: 0;
32 | &:hover,
33 | &[aria-current='page'],
34 | &.active {
35 | background-color: var(--color-neutral-muted);
36 | }
37 | &.active {
38 | background-color: var(--color-neutral-muted);
39 | gap: 5px;
40 | }
41 | `;
42 |
43 | export const MenuA = styled.a`
44 | display: flex;
45 | text-decoration: none;
46 | justify-content: flex-start;
47 | align-items: stretch;
48 | padding: 5px 12px;
49 | border-radius: 4px;
50 | color: currentColor;
51 | margin-left: 0;
52 | &:hover,
53 | &[aria-current='page'],
54 | &.active {
55 | background-color: var(--color-neutral-muted);
56 | }
57 | &.active {
58 | background-color: var(--color-neutral-muted);
59 | gap: 5px;
60 | }
61 | `;
62 |
63 | export const Divider = styled.div`
64 | font-size: 20px;
65 | font-weight: bold;
66 | padding: 15px 5px 5px 5px;
67 | color: var(--color-fg-default);
68 | `;
69 |
--------------------------------------------------------------------------------
/examples/website/src/components/Layouts/Navbar/index.tsx:
--------------------------------------------------------------------------------
1 | import { FC, PropsWithRef } from 'react';
2 | import { Link } from '@kkt/pro';
3 | import Icon from '@uiw/react-icon';
4 | import {
5 | Wrapper,
6 | Left,
7 | Right,
8 | Logo,
9 | HeaderTools,
10 | Title,
11 | Version,
12 | LinkMenu,
13 | AMenu,
14 | } from './style';
15 |
16 | interface NavbarProps
17 | extends React.DetailedHTMLProps<
18 | React.HTMLAttributes,
19 | HTMLElement
20 | > {}
21 |
22 | const Navbar: FC> = (props) => {
23 | return (
24 |
25 |
26 |
27 |
28 |
29 | UIW ADMIN{VERSION}
30 |
31 |
32 |
33 |
34 | 首页
35 |
39 | 实例预览
40 |
41 | 教程
42 | 组件
43 |
44 |
45 |
46 |
51 |
52 |
53 |
54 |
55 | );
56 | };
57 |
58 | export default Navbar;
59 |
--------------------------------------------------------------------------------
/examples/website/src/components/Layouts/Navbar/style.ts:
--------------------------------------------------------------------------------
1 | import styled from 'styled-components';
2 | import { NavLink } from '@kkt/pro';
3 |
4 | export const Wrapper = styled.div`
5 | border-bottom: 1px solid var(--color-border-muted);
6 | height: 58px;
7 | display: flex;
8 | align-items: center;
9 | justify-content: space-between;
10 | position: fixed;
11 | padding: 0 12px;
12 | gap: 12px;
13 | top: 0;
14 | width: 100%;
15 | z-index: 9;
16 | background-color: var(--color-canvas-default);
17 | /* background-color: hsla(var(--color-header-bg) / 75%);
18 | backdrop-filter: saturate(180%) blur(0.4rem); */
19 | `;
20 |
21 | export const Left = styled.div`
22 | display: flex;
23 | align-items: center;
24 | height: 58px;
25 | `;
26 |
27 | export const Right = styled.div`
28 | display: flex;
29 | align-items: center;
30 | height: 58px;
31 | `;
32 |
33 | export const Logo = styled(NavLink)`
34 | color: currentColor;
35 | padding: 0 0 0 10px;
36 | display: flex;
37 | align-items: center;
38 | gap: 10px;
39 | text-decoration: none;
40 | `;
41 |
42 | export const Title = styled.div`
43 | font-weight: bold;
44 | font-size: 18px;
45 | `;
46 |
47 | export const Version = styled.span`
48 | font-size: 12px;
49 | margin-left: 10px;
50 | font-weight: normal;
51 | position: relative;
52 | top: -5px;
53 | `;
54 |
55 | export const HeaderTools = styled.div`
56 | margin-right: 10px;
57 | font-size: 20px;
58 | margin-left: 20px;
59 | `;
60 |
61 | export const LinkMenu = styled(NavLink)`
62 | text-decoration: none;
63 | font-size: 16px;
64 | color: var(--color-fg-default);
65 | padding: 2px 15px;
66 | border-radius: 3px;
67 | &:first-child {
68 | margin-left: 0;
69 | }
70 | &.active {
71 | color: var(--font-color);
72 | background: var(--color1);
73 | }
74 | `;
75 | export const AMenu = styled.a`
76 | text-decoration: none;
77 | font-size: 16px;
78 | color: var(--color-fg-default);
79 | padding: 2px 15px;
80 | border-radius: 3px;
81 | &:first-child {
82 | margin-left: 0;
83 | }
84 | &.active {
85 | color: var(--font-color);
86 | background: var(--color1);
87 | }
88 | `;
89 |
--------------------------------------------------------------------------------
/examples/website/src/components/Layouts/index/index.tsx:
--------------------------------------------------------------------------------
1 | import { Outlet, KktproPageProps, useLocation } from '@kkt/pro';
2 | import Menu from '../Menu';
3 | import Navbar from '../Navbar';
4 | import { createGlobalStyle } from 'styled-components';
5 | import { Wrapper, Main, Body, OutletWrap } from './style';
6 | import '@wcj/dark-mode';
7 |
8 | export const GlobalStyle = createGlobalStyle`
9 | [data-color-mode*='dark'], [data-color-mode*='dark'] body {
10 | --gradient-from: #1c1e20;
11 | --gradient-to: #0d1117;
12 | --color-rgb: 255 255 255;
13 | }
14 | [data-color-mode*='light'], [data-color-mode*='light'] body {
15 | --gradient-from: #e5eaf0;
16 | --gradient-to: #fff;
17 | --color-rgb: 0 0 0;
18 | }
19 | `;
20 |
21 | export default function Layout(props: KktproPageProps) {
22 | const { pathname } = useLocation();
23 | const isHome: boolean = pathname === '/home';
24 |
25 | return (
26 |
27 |
28 |
29 |
30 |
31 | {!isHome && }
32 |
33 |
34 |
35 |
36 |
37 |
38 | );
39 | }
40 |
--------------------------------------------------------------------------------
/examples/website/src/components/Layouts/index/style.ts:
--------------------------------------------------------------------------------
1 | import styled, { css } from 'styled-components';
2 |
3 | export const Wrapper = styled.div`
4 | width: 100%;
5 | height: 100%;
6 | `;
7 |
8 | export const Main = styled.main`
9 | box-sizing: border-box;
10 | display: block;
11 | height: 100%;
12 | overflow: auto;
13 | scroll-behavior: smooth;
14 | `;
15 |
16 | export const Body = styled.div<{ isHome?: boolean }>`
17 | max-width: 1400px;
18 | margin: 0 auto;
19 | height: 100%;
20 | width: 100%;
21 | position: relative;
22 | z-index: 1;
23 | ${({ isHome }) => {
24 | return (
25 | isHome &&
26 | css`
27 | max-width: 100%;
28 | `
29 | );
30 | }}
31 | `;
32 |
33 | export const OutletWrap = styled.div<{ isHome?: boolean }>`
34 | padding-top: 58px;
35 | height: 100%;
36 | padding-left: 240px;
37 | ${({ isHome }) => {
38 | return (
39 | isHome &&
40 | css`
41 | padding-left: 0;
42 | `
43 | );
44 | }}
45 | `;
46 |
--------------------------------------------------------------------------------
/examples/website/src/components/Loading/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Wrapper, LoadBox } from './style';
3 |
4 | const Loading = ({
5 | children,
6 | loading,
7 | }: {
8 | children: React.ReactNode;
9 | loading?: boolean;
10 | }) => {
11 | return (
12 |
13 | {children}
14 | {loading && Loading...}
15 |
16 | );
17 | };
18 |
19 | export default Loading;
20 |
--------------------------------------------------------------------------------
/examples/website/src/components/Loading/style.ts:
--------------------------------------------------------------------------------
1 | import styled from 'styled-components';
2 |
3 | export const Wrapper = styled.div`
4 | position: relative;
5 | `;
6 |
7 | export const LoadBox = styled.div`
8 | position: absolute;
9 | left: 50%;
10 | transform: translateX(-50%);
11 | top: 200px;
12 | `;
13 |
--------------------------------------------------------------------------------
/examples/website/src/components/Preview/nodes/toc.less:
--------------------------------------------------------------------------------
1 | .menu-toc {
2 | padding-left: 23px;
3 | .menu-modal {
4 | padding-top: 23px;
5 | position: sticky;
6 | top: 40px;
7 | z-index: 999;
8 | right: 0;
9 | }
10 | .menu-marker {
11 | height: 18px;
12 | width: 5px;
13 | background-color: #f38701;
14 | position: absolute;
15 | margin-left: -5px;
16 | margin-top: 3px;
17 | border-radius: 2px;
18 | transition: top 0.3s;
19 | }
20 | a {
21 | display: block;
22 | height: 100%;
23 | text-overflow: ellipsis;
24 | white-space: nowrap;
25 | overflow: hidden;
26 | padding-left: 8px;
27 | &.active {
28 | text-decoration: underline;
29 | font-weight: bold;
30 | }
31 | }
32 | a + a {
33 | margin-top: 5px;
34 | }
35 | .level1 {
36 | font-weight: bold;
37 | color: var(--color-theme-text);
38 | }
39 | .level3,
40 | .level4,
41 | .level5,
42 | .level6 {
43 | padding-left: 18px;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/examples/website/src/components/Preview/nodes/toc.tsx:
--------------------------------------------------------------------------------
1 | import { Element, RootContent } from 'hast';
2 | import { getCodeString } from 'rehype-rewrite';
3 |
4 | export const titleNum = (tagName = '') => Number(tagName.replace(/^h/, ''));
5 | export function getTocTree(
6 | arr: RootContent[] = [],
7 | result: Element[] = [],
8 | ): Element {
9 | let n = 0;
10 | while (n < arr.length) {
11 | const toc = arr[n];
12 | if (toc && toc.type === 'element' && /^h[1-6]/.test(toc.tagName)) {
13 | const titleNum = Number(toc.tagName.replace(/^h/, ''));
14 | result.push({
15 | ...toc,
16 | tagName: 'a',
17 | properties: {
18 | class: `toc-link level${titleNum}`,
19 | href: `#${toc.properties?.id}`,
20 | },
21 | children: [
22 | {
23 | type: 'text',
24 | value: getCodeString(toc.children),
25 | },
26 | ],
27 | });
28 | }
29 | n++;
30 | }
31 | return {
32 | type: 'element',
33 | tagName: 'nav',
34 | properties: {
35 | class: 'menu-toc',
36 | id: 'menu-toc',
37 | },
38 | children: [
39 | {
40 | type: 'element',
41 | tagName: 'aside',
42 | properties: {
43 | class: 'menu-modal',
44 | 'data-top': '12px',
45 | },
46 | children: [
47 | {
48 | type: 'element',
49 | tagName: 'div',
50 | properties: {
51 | class: 'menu-marker',
52 | },
53 | children: [],
54 | },
55 | ...result,
56 | ],
57 | },
58 | ],
59 | };
60 | }
61 |
--------------------------------------------------------------------------------
/examples/website/src/components/Preview/useMdData.ts:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from 'react';
2 | import { CodeBlockData } from 'markdown-react-code-preview-loader';
3 |
4 | export type MdDataHandle = () => Promise<{ default: CodeBlockData }>;
5 |
6 | export const useMdData = (path: MdDataHandle) => {
7 | const [mdData, setMdData] = useState({
8 | source: '',
9 | components: {},
10 | data: {},
11 | });
12 | const [loading, setLoading] = useState(false);
13 |
14 | useEffect(() => {
15 | const $main = document.getElementsByTagName(
16 | 'main',
17 | ) as HTMLCollectionOf;
18 | $main[0].scrollTo(0, 0);
19 | }, [path]);
20 |
21 | useEffect(() => {
22 | setLoading(() => true);
23 | const getMd = async () => {
24 | try {
25 | const result = await path();
26 | if (result.default) {
27 | setMdData(result.default);
28 | }
29 | } catch (err) {
30 | console.warn(err);
31 | }
32 | setLoading(() => false);
33 | };
34 | getMd();
35 | // eslint-disable-next-line
36 | }, [path]);
37 | return { mdData, loading };
38 | };
39 |
--------------------------------------------------------------------------------
/examples/website/src/global.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | -webkit-font-smoothing: antialiased;
4 | font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;
5 | font-size: 16px;
6 | }
7 |
8 | body, html, #root{
9 | height: 100%;
10 | padding: 0;
11 | margin: 0;
12 | }
13 |
14 | html, main {
15 | scroll-behavior: smooth;
16 | }
17 |
18 | *, :after, :before {
19 | box-sizing: border-box;
20 | }
21 |
22 |
23 | [data-color-mode*='light'] {
24 | --font-color: #333;
25 | --color-header-bg: 255 255 255;
26 | --color-border-muted: #e5e5e5;
27 | --color1: #f2f2f2;
28 | --color2: #1677ff;
29 | }
30 |
31 | [data-color-mode*='dark'] {
32 | --font-color: #fff;
33 | --color-header-bg: 13 17 22;
34 | --color-border-muted: #373737;
35 | --color1: #282828;
36 | --color2: #0053c8;
37 | }
38 |
39 | .menu-toc .menu-marker {
40 | background: var(--color-accent-fg) !important;
41 | }
--------------------------------------------------------------------------------
/examples/website/src/index.less:
--------------------------------------------------------------------------------
1 | body,
2 | html {
3 | font-size: 14px;
4 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial,
5 | sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol;
6 | }
7 |
8 | :global {
9 | #root {
10 | min-height: 100%;
11 | background-color: #f3f3f3;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/examples/website/src/pages/auth/README.md:
--------------------------------------------------------------------------------
1 | # 权限管理
2 |
3 | ## 一、简介
4 | 在项目中经常有的场景是不同的用户的权限不同,通常有如下场景:
5 | - 不同的用户在页面中可以看到的元素和操作不同
6 | - 不同的用户对页面的访问权限不同
7 |
8 | ```bash
9 | 针对这些场景,我们为中台场景下常用的权限控制提供了一种更加简单、易用、通用的解决方案。实现了一个基于 umi 插件的权限管
10 | 理方案 - @uiw-admin/authorized。通过定义权限,使用权限,完成 React 组件内的执行权限控制,渲染权限控制。搭配
11 | @uiw-admin/basic-layouts 插件一起使用,还可以进一步完成对路由权限的控制。
12 | ```
13 |
14 | ## 二、路由和菜单
15 | 当项目需要根据权限判断组件是否展示 使用组件时,在 `.kktprc.ts`文件中配置全局变量
16 |
17 | ```diff
18 | export default {
19 | define:{
20 | + AUTH:true,
21 | // ...
22 | }
23 | // ...
24 | }
25 | ```
26 | 如果是路由权限判断,请在route.json中添加对应菜单的权限``isAuth``
27 | ```json
28 | [
29 | {
30 | "path": "/new",
31 | "name": "新页面",
32 | "element": "@page/NewPage",
33 | "icon": "home",
34 | "isAuth":true
35 | },
36 | ]
37 | ```
38 |
39 | 然后在BasicLayout.tsx,使用 ``AuthPage``组件
40 | ```jsx
41 | import AuthPage from "@uiw-admin/authorized"
42 | import BasicLayout from '@uiw-admin/BasicLayout'
43 | export default ()=>{
44 | return (
45 |
46 |
47 |
48 | )
49 | }
50 | ```
51 |
52 | ## 三、页面中控件权限控制
53 | ```jsx
54 | import React from "react"
55 | import { AuthBtn } from "@uiw-admin/authorized"
56 |
57 | const Demos = ()=>{
58 | return (
59 |
60 |
61 | 子集渲染1
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 | )
74 | }
75 | export default Demos
76 | ```
--------------------------------------------------------------------------------
/examples/website/src/pages/auth/index.tsx:
--------------------------------------------------------------------------------
1 | import Preview from '../../components/Preview';
2 |
3 | const Page = () => import('./README.md')} />;
4 |
5 | export default Page;
6 |
--------------------------------------------------------------------------------
/examples/website/src/pages/authorized/index.tsx:
--------------------------------------------------------------------------------
1 | import Preview from '../../components/Preview';
2 |
3 | const Page = () => (
4 | import('@uiw-admin/authorized/README.md')} />
5 | );
6 |
7 | export default Page;
8 |
--------------------------------------------------------------------------------
/examples/website/src/pages/basic-layouts/index.tsx:
--------------------------------------------------------------------------------
1 | import Preview from '../../components/Preview';
2 |
3 | const Page = () => (
4 | import('@uiw-admin/basic-layouts/README.md')} />
5 | );
6 |
7 | export default Page;
8 |
--------------------------------------------------------------------------------
/examples/website/src/pages/components/ProDrawer.tsx:
--------------------------------------------------------------------------------
1 | import Preview from '../../components/Preview';
2 |
3 | const Page = () => (
4 | import('@uiw-admin/components/src/ProDrawer/README.md')}
6 | />
7 | );
8 |
9 | export default Page;
10 |
--------------------------------------------------------------------------------
/examples/website/src/pages/components/ProForm.tsx:
--------------------------------------------------------------------------------
1 | import Preview from '../../components/Preview';
2 |
3 | const Page = () => (
4 | import('@uiw-admin/components/src/ProForm/README.md')} />
5 | );
6 |
7 | export default Page;
8 |
--------------------------------------------------------------------------------
/examples/website/src/pages/components/Protable.tsx:
--------------------------------------------------------------------------------
1 | import Preview from '../../components/Preview';
2 |
3 | const Page = () => (
4 | import('@uiw-admin/components/src/ProTable/README.md')}
6 | />
7 | );
8 |
9 | export default Page;
10 |
--------------------------------------------------------------------------------
/examples/website/src/pages/components/Skeleton.tsx:
--------------------------------------------------------------------------------
1 | import Preview from '../../components/Preview';
2 |
3 | const Page = () => (
4 | import('@uiw-admin/components/src/Skeleton/README.md')}
6 | />
7 | );
8 |
9 | export default Page;
10 |
--------------------------------------------------------------------------------
/examples/website/src/pages/components/index.tsx:
--------------------------------------------------------------------------------
1 | import Preview from '../../components/Preview';
2 |
3 | const Page = () => (
4 | import('@uiw-admin/components/README.md')} />
5 | );
6 |
7 | export default Page;
8 |
--------------------------------------------------------------------------------
/examples/website/src/pages/config/index.tsx:
--------------------------------------------------------------------------------
1 | import Preview from '../../components/Preview';
2 |
3 | const Page = () => (
4 | import('@uiw-admin/config/README.md')} />
5 | );
6 |
7 | export default Page;
8 |
--------------------------------------------------------------------------------
/examples/website/src/pages/document-title/index.tsx:
--------------------------------------------------------------------------------
1 | import Preview from '../../components/Preview';
2 |
3 | const Page = () => (
4 | import('@uiw-admin/document-title/README.md')} />
5 | );
6 |
7 | export default Page;
8 |
--------------------------------------------------------------------------------
/examples/website/src/pages/eslint-config/README.md:
--------------------------------------------------------------------------------
1 | ../../../../../eslint-packages/config/README.md
--------------------------------------------------------------------------------
/examples/website/src/pages/eslint-config/index.tsx:
--------------------------------------------------------------------------------
1 | import Preview from '../../components/Preview';
2 |
3 | const Page = () => import('./README.md')} />;
4 |
5 | export default Page;
6 |
--------------------------------------------------------------------------------
/examples/website/src/pages/example/index.module.css:
--------------------------------------------------------------------------------
1 |
2 | .loading {
3 | position: absolute;
4 | z-index: 9999;
5 | height: 100vh;
6 | width: 100%;
7 | backdrop-filter: saturate(180%) blur(.4rem);
8 | background-color: hsla(0,0%,100%,.75);
9 | display: flex;
10 | flex-direction: column;
11 | justify-content: center;
12 | align-items: center;
13 | }
14 |
15 | .tools {
16 | position: fixed;
17 | z-index: 99999;
18 | bottom: 10px;
19 | left: 10px;
20 | }
--------------------------------------------------------------------------------
/examples/website/src/pages/example/index.tsx:
--------------------------------------------------------------------------------
1 | import { Fragment, useState } from 'react';
2 | import { useNavigate } from 'react-router-dom';
3 | import { Button, Loader, Icon } from 'uiw';
4 | import styles from './index.module.css';
5 |
6 | export default function Page() {
7 | const [loading, setLoading] = useState(true);
8 | const navigate = useNavigate();
9 | return (
10 |
11 | {loading && (
12 |
13 |
14 |
15 | )}
16 |
17 |
20 |
21 |
40 | );
41 | }
42 |
--------------------------------------------------------------------------------
/examples/website/src/pages/exceptions/index.tsx:
--------------------------------------------------------------------------------
1 | import Preview from '../../components/Preview';
2 |
3 | const Page = () => (
4 | import('@uiw-admin/exceptions/README.md')} />
5 | );
6 |
7 | export default Page;
8 |
--------------------------------------------------------------------------------
/examples/website/src/pages/home/index.tsx:
--------------------------------------------------------------------------------
1 | import { Wrap, Hero, BtnGroup, LinkMenu, LinkA, Footer } from './style';
2 |
3 | const Page = () => {
4 | return (
5 |
6 |
7 | UIW ADMNIN
8 |
9 | 一个基于{' '}
10 |
11 | uiw
12 | {' '}
13 | 和{' '}
14 |
15 | @kkt/pro
16 | {' '}
17 | 的初始级别项目
18 |
19 |
20 | 立即上手
21 |
22 | GitHub
23 |
24 |
25 |
26 |
42 |
43 | );
44 | };
45 | export default Page;
46 |
--------------------------------------------------------------------------------
/examples/website/src/pages/home/style.ts:
--------------------------------------------------------------------------------
1 | import styled, { css } from 'styled-components';
2 | import { NavLink } from '@kkt/pro';
3 |
4 | export const Wrap = styled.div`
5 | padding: 100px 0 50px;
6 | `;
7 |
8 | export const Hero = styled.div`
9 | display: flex;
10 | flex-direction: column;
11 | align-items: center;
12 | margin-bottom: 100px;
13 | h1 {
14 | font-size: 100px;
15 | text-shadow: 0 10px 20px rgba(22, 119, 255, 0.15);
16 | background: linear-gradient(30deg, #90d5ff 30%, #65a5ff);
17 | -webkit-background-clip: text;
18 | background-clip: text;
19 | font-family: Alibaba-PuHuiTi, Gill Sans, Gill Sans MT, Calibri, Trebuchet MS,
20 | sans-serif;
21 | color: #83cdf8;
22 | }
23 | p {
24 | font-size: 20px;
25 | line-height: 1;
26 | margin: 30px 0;
27 | a {
28 | color: var(--color2);
29 | text-decoration: none;
30 | &:hover {
31 | text-decoration: underline;
32 | }
33 | }
34 | }
35 | `;
36 | export const BtnGroup = styled.div`
37 | display: flex;
38 | align-items: center;
39 | justify-content: center;
40 | margin-top: 50px;
41 | `;
42 |
43 | const defaultBtn = (active?: boolean) => {
44 | const background = active ? `var(--color2)` : 'transparent';
45 | const color = active ? '#fff' : 'var(--color2)';
46 | return css`
47 | text-decoration: none;
48 | font-size: 18px;
49 | color: var(--color-fg-default);
50 | padding: 2px 15px;
51 | border-radius: 3px;
52 | height: 50px;
53 | width: 150px;
54 | border-radius: 25px;
55 | background-color: ${background};
56 | border: 1px solid var(--color2);
57 | color: ${color};
58 | display: flex;
59 | align-items: center;
60 | justify-content: center;
61 | opacity: 0.8;
62 | margin: 0 20px;
63 | &:hover {
64 | opacity: 1;
65 | }
66 | `;
67 | };
68 |
69 | export const LinkMenu = styled(NavLink)`
70 | ${() => defaultBtn(true)}
71 | `;
72 |
73 | export const LinkA = styled.a`
74 | ${() => defaultBtn()}
75 | `;
76 |
77 | export const Footer = styled.div`
78 | max-width: 1200px;
79 | margin: 0 auto;
80 | margin-top: 50px;
81 | text-align: center;
82 | border-top: 1px solid var(--color-border-muted);
83 | padding-top: 50px;
84 | h3 {
85 | font-size: 30px;
86 | margin: 0;
87 | }
88 | p {
89 | margin: 15px;
90 | }
91 | `;
92 |
--------------------------------------------------------------------------------
/examples/website/src/pages/layout-tabs/index.tsx:
--------------------------------------------------------------------------------
1 | import Preview from '../../components/Preview';
2 |
3 | const Page = () => (
4 | import('@uiw-admin/layout-tabs/README.md')} />
5 | );
6 |
7 | export default Page;
8 |
--------------------------------------------------------------------------------
/examples/website/src/pages/mocker/README.md:
--------------------------------------------------------------------------------
1 | # mocker
2 |
3 | 为了方便前期前端快速开发,不需要等待后端接口,系统提供了mock功能。更多配置请参考[mocker-api](https://github.com/jaywcjlove/mocker-api)
4 |
5 | ## 编写mock
6 |
7 | > 在/mocker/index目录下进行mock数据编写,比如:
8 |
9 | ```ts
10 | const { delay } = require('mocker-api');
11 | const noProxy = process.env.NO_PROXY === 'true';
12 |
13 | const proxy = {
14 | 'GET /api/user/list': [
15 | {
16 | id: 1,
17 | username: 'kenny',
18 | sex: 6
19 | }, {
20 | id: 2,
21 | username: 'kenny',
22 | sex: 6
23 | }
24 | ],
25 | 'POST /api/login/account': (req, res) => {
26 | const { password, username } = req.body;
27 | if (password === '888888' && username === 'admin') {
28 | return res.json({
29 | status: 'ok',
30 | code: 0,
31 | token: "sdfsdfsdfdsf",
32 | data: {
33 | id: 1,
34 | username: 'kenny',
35 | sex: 6
36 | }
37 | });
38 | } else {
39 | return res.status(403).json({
40 | status: 'error',
41 | code: 403
42 | });
43 | }
44 | },
45 | }
46 | module.exports = (noProxy ? {} : delay(proxy, 1000));
47 | ```
48 |
49 | ## 调用
50 |
51 | > 配合系统封装的request进行mock数据请求。如需区分是mock数据,还是真实后端数据,调用真实数据时,注释mocker数据配置即可
52 |
53 | ```ts
54 | import { request } from "@uiw-admin/utils"
55 |
56 | export const selectById = (params:{id:string}) => request("/api/login/account",{ method:"POST",body: { ...params } })
57 | ```
58 |
59 | 注:mock功能只推荐在开发模式下开启。
60 |
61 |
62 | ## 贡献者
63 |
64 | 感谢所有的贡献者,欢迎开发者为开源项目贡献力量。
65 |
66 |
67 |
68 |
69 |
70 | ## License
71 |
72 | Licensed under the MIT License.
73 |
--------------------------------------------------------------------------------
/examples/website/src/pages/mocker/index.tsx:
--------------------------------------------------------------------------------
1 | import Preview from '../../components/Preview';
2 |
3 | const Page = () => import('./README.md')} />;
4 |
5 | export default Page;
6 |
--------------------------------------------------------------------------------
/examples/website/src/pages/models/index.tsx:
--------------------------------------------------------------------------------
1 | import Preview from '../../components/Preview';
2 |
3 | const Page = () => import('./README.md')} />;
4 |
5 | export default Page;
6 |
--------------------------------------------------------------------------------
/examples/website/src/pages/navbar/index.tsx:
--------------------------------------------------------------------------------
1 | import Preview from '../../components/Preview';
2 |
3 | const Page = () => (
4 | import('@uiw-admin/markdown-navbar/README.md')} />
5 | );
6 |
7 | export default Page;
8 |
--------------------------------------------------------------------------------
/examples/website/src/pages/newPages/README.md:
--------------------------------------------------------------------------------
1 | # 新增页面
2 | 这里的『页面』指配置了路由,能够通过链接直接访问的模块,要新建一个页面,通常可以在脚手架的基础上进行简单的配置。
3 |
4 | ## 页面代码结构推荐
5 | 为了让项目代码组织更加规范,让开发能够更方便的定位到相关页面组件代码,我们定义了一套规范,该规范当前只作为推荐的指导,并非强制。
6 | ```bash
7 | src
8 | ├── components
9 | └── pages
10 | ├── Welcome // 路由组件下不应该再包含其他路由组件,基于这个约定就能清楚的区分路由组件和非路由组件了
11 | | ├── components // 对于复杂的页面可以再自己做更深层次的组织,但建议不要超过三层
12 | | ├── Form.tsx
13 | | ├── index.tsx // 页面组件的代码
14 | | └── index.less // 页面样式
15 | ├── Order // 路由组件下不应该再包含其他路由组件,基于这个约定就能清楚的区分路由组件和非路由组件了
16 | | ├── index.tsx
17 | | └── index.less
18 | ├── User
19 | | ├── components // group 下公用的组件集合
20 | | ├── Login // group 下的页面 Login
21 | | ├── Register // group 下的页面 Register
22 | | └── util.ts // 这里可以有一些共用方法之类,不做推荐和约束,看业务场景自行做组织
23 | └── * // 其它页面组件代码
24 | ```
25 |
26 | 所有路由组件(会配置在路由配置中的组件)我们推荐以大驼峰命名打平到 pages 下面第一级(复杂的项目可以增加 group 层级,在 group 下放置 pages)。不建议在路由组件内部再嵌套路由组件 - 不方便分辨一个组件是否是路由组件,而且不方便快速从全局定位到路由组件。
27 |
28 | 我们推荐尽可能的拆分路由组件为更细粒度的组件,对于多个页面可能会用到的组件我们推荐放到 src/components 中,对于只是被单个页面依赖的(区块)组件,我们推荐就近维护到路由组件文件夹下即可。
29 |
30 | ## 手动创建
31 | 新增 ts、less 文件
32 | 在 src / pages 下创建新的 tsx,less 文件。 如果有多个相关页面,您可以创建一个新文件夹来放置相关文件。
33 |
34 | ```bash
35 | config
36 | src
37 | models
38 | pages
39 | + NewPage
40 | + index.less
41 | + index.tsx
42 | ...
43 | ...
44 | package.json
45 | ```
46 | 为了更好的演示,我们初始化NewPage.js的内容如下:
47 | ```bash
48 | export default () => {
49 | return New Page
;
50 | };
51 | ```
52 |
53 | ## 新增路由
54 | 在脚手架中我们通过嵌套路由来实现布局模板。config文件中的routes.json 是一个数组,其中第一级数据就是我们的布局,如果你需要新增布局可以再直接增加一个新的一级数据。
55 | ```json
56 | [
57 | {
58 | "path": "/dom",
59 | "name": "子项",
60 | "icon": "copy",
61 | "children": [...]
62 | },
63 | // new
64 | {
65 | "path": "/new",
66 | "name": "新页面",
67 | "element": "@page/NewPage",
68 | "icon": "home"
69 | },
70 | ]
71 | ```
72 |
73 | 路由配置完成后,访问页面即可看到效果,如果需要在菜单中显示,需要配置 name,icon,hideInMenu等来辅助生成菜单。
74 |
75 | 具体值如下:
76 |
77 | - ``key``
78 | - ``index`` 默认跳转
79 | - ``path`` 路径
80 | - ``name`` 名称
81 | - ``icon`` 图标
82 | - ``redirect`` 重定向
83 | - ``children`` 子集 路由
84 | - ``hiddenMainMenu`` 隐藏主菜单
85 | - ``hideInMenu`` 是否隐藏菜单
86 | - ``isAuth`` 用于路由校验权限
87 | - ``navigate`` 自定义 跳转
88 | - ``side`` 控制是否侧边只展示子路由
89 |
90 | 布局及路由都配置好之后,回到之前新建的 ```index.tsx```,可以开始写业务代码了!
91 |
92 | ## 贡献者
93 |
94 | 感谢所有的贡献者,欢迎开发者为开源项目贡献力量。
95 |
96 |
97 |
98 |
99 |
100 | ## License
101 |
102 | Licensed under the MIT License.
--------------------------------------------------------------------------------
/examples/website/src/pages/newPages/index.tsx:
--------------------------------------------------------------------------------
1 | import Preview from '../../components/Preview';
2 |
3 | const Page = () => import('./README.md')} />;
4 |
5 | export default Page;
6 |
--------------------------------------------------------------------------------
/examples/website/src/pages/plugins/index.tsx:
--------------------------------------------------------------------------------
1 | import Preview from '../../components/Preview';
2 |
3 | const Page = () => (
4 | import('@uiw-admin/plugins/README.md')} />
5 | );
6 |
7 | export default Page;
8 |
--------------------------------------------------------------------------------
/examples/website/src/pages/proxy/index.tsx:
--------------------------------------------------------------------------------
1 | import Preview from '../../components/Preview';
2 |
3 | const Page = () => import('./README.md')} />;
4 |
5 | export default Page;
6 |
--------------------------------------------------------------------------------
/examples/website/src/pages/quick-start/README.md:
--------------------------------------------------------------------------------
1 | ../../../../../packages/uiw-admin/README.md
--------------------------------------------------------------------------------
/examples/website/src/pages/quick-start/index.tsx:
--------------------------------------------------------------------------------
1 | import Preview from '../../components/Preview';
2 |
3 | const Page = () => import('./README.md')} />;
4 |
5 | export default Page;
6 |
--------------------------------------------------------------------------------
/examples/website/src/pages/request/index.tsx:
--------------------------------------------------------------------------------
1 | import Preview from '../../components/Preview';
2 |
3 | const Page = () => import('./README.md')} />;
4 |
5 | export default Page;
6 |
--------------------------------------------------------------------------------
/examples/website/src/pages/router-control/index.tsx:
--------------------------------------------------------------------------------
1 | import Preview from '../../components/Preview';
2 |
3 | const Page = () => (
4 | import('@uiw-admin/router-control/README.md')} />
5 | );
6 |
7 | export default Page;
8 |
--------------------------------------------------------------------------------
/examples/website/src/pages/user-login/Example.tsx:
--------------------------------------------------------------------------------
1 | import styled, { css } from 'styled-components';
2 | import { Link } from '@kkt/pro';
3 | import UserLogin from '@uiw-admin/user-login';
4 | import * as datas from './Examples';
5 |
6 | const Wrapper = styled.div`
7 | display: flex;
8 | justify-content: center;
9 | margin: 0 auto;
10 | flex-wrap: wrap;
11 | gap: 0.953rem;
12 | `;
13 |
14 | const Title = styled.div`
15 | width: auto !important;
16 | height: auto !important;
17 | position: absolute;
18 | transform: scale(1) !important;
19 | background-color: rgba(var(--color-rgb) / 39%);
20 | color: var(--color-canvas-default);
21 | border-radius: 5px;
22 | padding: 1px 4px 3px 4px;
23 | top: -25px;
24 | left: 10px;
25 | transition: all 0.3s;
26 | `;
27 |
28 | const Inner = styled(Link)<{ magnify?: number }>`
29 | overflow: hidden;
30 | display: block;
31 | position: relative;
32 | width: 326px;
33 | height: 265px;
34 | border-radius: 0.571rem;
35 | text-decoration: none;
36 | box-shadow: 0 0px 3px transparent;
37 | border: 1px solid transparent;
38 | transition: all 0.3s;
39 | &::before {
40 | content: '';
41 | display: block;
42 | position: absolute;
43 | background-color: transparent;
44 | transition: all 0.3s;
45 | z-index: 2;
46 | inset: 0;
47 | }
48 | &:hover {
49 | box-shadow: 0 0px 3px rgba(0, 0, 0, 0.1);
50 | border-color: rgb(0 0 0 / 11%);
51 | }
52 | &:hover ${Title} {
53 | top: 10px;
54 | }
55 | &:hover::before {
56 | background-color: var(--color-neutral-muted);
57 | }
58 | & > * {
59 | transform-origin: top left;
60 | ${({ magnify = 2 }) => css`
61 | transform: scale(${326 / (326 * magnify)});
62 | width: ${326 * magnify}px;
63 | height: ${265 * magnify}px;
64 | `}
65 | }
66 | `;
67 |
68 | const defulat = {
69 | magnify: 2.3,
70 | children: ,
71 | };
72 |
73 | export const Example = () => {
74 | return (
75 |
76 |
81 | {defulat.children}
82 | defulat
83 |
84 | {Object.keys(datas).map((path, key) => {
85 | const comps = datas[path as keyof typeof datas];
86 | return (
87 |
93 | {comps.children}
94 | {path}
95 |
96 | );
97 | })}
98 |
99 | );
100 | };
101 |
--------------------------------------------------------------------------------
/examples/website/src/pages/user-login/Examples.tsx:
--------------------------------------------------------------------------------
1 | import LoginBase from '@react-login-page/base';
2 | import LoginLogo from 'react-login-page/logo-rect';
3 | import LoginPage1 from '@react-login-page/page1';
4 | import LoginPage2 from '@react-login-page/page2';
5 | // import bannerImage from '@react-login-page/page2/banner-image';
6 | import LoginPage3 from '@react-login-page/page3';
7 | // import bannerImage3 from '@react-login-page/page3/banner-image';
8 | import Login4 from '@react-login-page/page4';
9 | import Login5 from '@react-login-page/page5';
10 | import Login6 from '@react-login-page/page6';
11 | import Login7 from '@react-login-page/page7';
12 |
13 | const bannerImage = require('@react-login-page/page2/banner-image');
14 | const bannerImage3 = require('@react-login-page/page3/banner-image');
15 |
16 | interface Example {
17 | magnify?: number;
18 | children?: JSX.Element;
19 | }
20 |
21 | export const base: Example = {
22 | magnify: 1.3,
23 | children: (
24 |
25 |
26 |
27 |
28 |
29 | ),
30 | };
31 |
32 | export const page1: Example = {
33 | children: (
34 |
35 |
36 |
37 |
38 |
39 | ),
40 | };
41 |
42 | export const page2: Example = {
43 | magnify: 3.3,
44 | children: (
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 | ),
54 | };
55 |
56 | export const page3: Example = {
57 | children: (
58 |
59 |
60 |
61 |
62 |
63 |
64 | ),
65 | };
66 |
67 | export const page4: Example = {
68 | magnify: 2.3,
69 | children: (
70 |
71 |
72 |
73 |
74 |
75 | ),
76 | };
77 |
78 | export const page5: Example = {
79 | magnify: 1.6,
80 | children: (
81 |
82 |
83 |
84 |
85 |
86 | ),
87 | };
88 |
89 | export const page6: Example = {
90 | magnify: 2.1,
91 | children: (
92 |
93 |
94 |
95 |
96 |
97 | ),
98 | };
99 |
100 | export const page7: Example = {
101 | magnify: 1.2,
102 | children: (
103 |
104 |
105 |
106 |
107 |
108 | ),
109 | };
110 |
--------------------------------------------------------------------------------
/examples/website/src/pages/user-login/index.tsx:
--------------------------------------------------------------------------------
1 | import styled from 'styled-components';
2 | import { Link } from '@kkt/pro';
3 | import { ReactComponent as LogoIcon } from './logo-large.svg';
4 | import { Example } from './Example';
5 |
6 | const Wrapper = styled.div`
7 | width: 100%;
8 | position: relative;
9 | z-index: 9;
10 | padding-bottom: 60px;
11 | `;
12 |
13 | const Title = styled.h1`
14 | font-size: 1.6rem;
15 | font-weight: 900;
16 | line-height: 2.5rem;
17 | text-align: center;
18 | margin-top: 3rem;
19 | margin-bottom: 0;
20 | `;
21 | const SubTitle = styled.h2`
22 | color: var(--color-fg-subtle);
23 | font-size: 1.5rem;
24 | font-weight: normal;
25 | line-height: 2rem;
26 | text-align: center;
27 | max-width: 36rem;
28 | margin: 0.75rem auto 2rem auto;
29 | `;
30 |
31 | const Logo = styled(LogoIcon)`
32 | margin: 60px auto;
33 | display: block;
34 | `;
35 |
36 | const Nav = styled.nav`
37 | text-align: center;
38 | margin-bottom: 3rem;
39 | gap: 0.845rem;
40 | display: flex;
41 | justify-content: center;
42 | a {
43 | padding: 0.63rem 1.1rem;
44 | font-weight: 700;
45 | background: var(--color-neutral-muted);
46 | border-radius: 0.3rem;
47 | transition: all 0.3s;
48 | text-decoration: none;
49 | &:hover {
50 | background: var(--color-canvas-subtle);
51 | }
52 | }
53 | `;
54 |
55 | const Header = styled.div``;
56 | const VersionInfo = styled.sup`
57 | text-align: center;
58 | color: var(--color-fg-subtle);
59 | position: absolute;
60 | font-size: 12px;
61 | font-weight: normal;
62 | margin-left: 10px;
63 | line-height: 12px;
64 | `;
65 |
66 | // const version = VERSION;
67 |
68 | const Home = () => {
69 | return (
70 |
71 |
74 |
75 | React Login Page
76 | {/* v{version} */}
77 |
78 |
79 | Install and use react login page components quickly and easily, with
80 | flexible APIs for modifying these components.
81 |
82 |
92 |
93 |
94 | );
95 | };
96 |
97 | export default Home;
98 |
--------------------------------------------------------------------------------
/examples/website/src/pages/user-login/index2.tsx:
--------------------------------------------------------------------------------
1 | import Preview from '../../components/Preview';
2 |
3 | const Page = () => (
4 |
6 | import(
7 | 'https://github.com/uiwjs/react-login-page/edit/main/core/README.md'
8 | )
9 | }
10 | />
11 | );
12 |
13 | export default Page;
14 |
--------------------------------------------------------------------------------
/examples/website/src/pages/utils/index.tsx:
--------------------------------------------------------------------------------
1 | import Preview from '../../components/Preview';
2 |
3 | const Page = () => (
4 | import('@uiw-admin/utils/README.md')} />
5 | );
6 |
7 | export default Page;
8 |
--------------------------------------------------------------------------------
/examples/website/src/react-app-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | declare module '*.md' {
4 | const value: any;
5 | export default value;
6 | }
7 |
8 | declare var VERSION: string;
9 |
10 | declare module '*.module.less' {
11 | const classes: { readonly [key: string]: string };
12 | export default classes;
13 | }
14 |
--------------------------------------------------------------------------------
/examples/website/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "esnext",
4 | "module": "esnext",
5 | "jsx": "react-jsx",
6 | "declaration": true,
7 | "strict": true,
8 | "allowSyntheticDefaultImports": true,
9 | "esModuleInterop": true,
10 | "importHelpers": true,
11 | "noImplicitAny": true,
12 | "resolveJsonModule": true,
13 | "sourceMap": true,
14 | "baseUrl": ".",
15 | "lib": ["dom", "dom.iterable", "esnext"],
16 | "allowJs": true,
17 | "skipLibCheck": true,
18 | "forceConsistentCasingInFileNames": true,
19 | "noFallthroughCasesInSwitch": true,
20 | "moduleResolution": "node",
21 | "isolatedModules": true,
22 | "types": ["jest", "node"],
23 | "noEmit": false,
24 | "outDir": "cjs",
25 | "paths": {
26 | "@/*": ["./src/*"],
27 | "@@/*": ["./src/.kktp/*"],
28 | "kktp": ["./src/.kktp/*"]
29 | }
30 | },
31 | "include": ["src", "config/.kktprc.ts"]
32 | }
33 |
--------------------------------------------------------------------------------
/lerna.json:
--------------------------------------------------------------------------------
1 | {
2 | "packages": [
3 | "packages/*",
4 | "examples/*",
5 | "create-uiw-admin",
6 | "eslint-packages/*"
7 | ],
8 | "version": "6.1.9",
9 | "command": {
10 | "create": {
11 | "license": "MIT"
12 | },
13 | "bootstrap": {
14 | "yarnClientArgs": ["--no-yarn-lock"],
15 | "npmClientArgs": ["--no-package-lock"],
16 | "forceLocal": true
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/packages/authorized/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@uiw-admin/authorized",
3 | "version": "6.1.9",
4 | "description": "authorized",
5 | "author": "Kenny Wong ",
6 | "homepage": "https://github.com/uiwjs/uiw-admin/tree/master/packages/authorized#readme",
7 | "license": "MIT",
8 | "main": "lib/index.js",
9 | "module": "esm/index.js",
10 | "files": [
11 | "lib",
12 | "esm",
13 | "src"
14 | ],
15 | "publishConfig": {
16 | "access": "public"
17 | },
18 | "keywords": [
19 | "design",
20 | "uiw",
21 | "uiw-react",
22 | "uiw-admin",
23 | "react.js",
24 | "react",
25 | "react-component",
26 | "component",
27 | "components",
28 | "ui",
29 | "css",
30 | "uikit",
31 | "react-ui",
32 | "framework",
33 | "front-end",
34 | "frontend"
35 | ],
36 | "repository": {
37 | "type": "git",
38 | "url": "git+https://github.com/uiwjs/uiw-admin.git"
39 | },
40 | "scripts": {
41 | "test": "echo \"Error: run tests from root\" && exit 1"
42 | },
43 | "peerDependencies": {
44 | "react": ">=17.x",
45 | "react-dom": ">=17.x"
46 | },
47 | "dependencies": {
48 | "@babel/runtime": "~7.21.0"
49 | },
50 | "devDependencies": {
51 | "@types/react": "~18.0.25",
52 | "@types/react-dom": "~18.0.11",
53 | "react": "18.2.0",
54 | "react-dom": "18.2.0",
55 | "react-router": "^6.8.0",
56 | "react-router-dom": "^6.8.0"
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/packages/authorized/src/Auth.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export const getAuthPath = (path?: string): boolean => {
4 | // @ts-ignore
5 | if (AUTH) {
6 | let authList: string[] = [];
7 |
8 | let authStr = sessionStorage.getItem('auth');
9 | // @ts-ignore
10 | if (STORAGE === 'local') {
11 | authStr = localStorage.getItem('auth');
12 | }
13 | if (authStr) {
14 | authList = JSON.parse(authStr);
15 | }
16 | const fig = authList.find((item) => item === path);
17 | return !!fig;
18 | }
19 | return true;
20 | };
21 |
22 | /** 校验按钮权限 */
23 | export interface AuthBtnProps {
24 | /** 路径 */
25 | path?: string;
26 | /** 禁用 状态 展示 适用于 存在 disabled 属性的组件 */
27 | disabled?: boolean;
28 | children: JSX.Element;
29 | }
30 | const AuthBtn = (props: AuthBtnProps) => {
31 | const { path, disabled, children } = props;
32 | const fig = React.useMemo(() => {
33 | // @ts-ignore
34 | if (AUTH) {
35 | return getAuthPath(path);
36 | }
37 | return true;
38 | }, [path]);
39 |
40 | if (fig) {
41 | return children;
42 | } else if (!fig && disabled && React.isValidElement(children)) {
43 | return React.cloneElement(children, { disabled } as any);
44 | }
45 | return ;
46 | };
47 |
48 | export default AuthBtn;
49 |
--------------------------------------------------------------------------------
/packages/authorized/src/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { useNavigate } from 'react-router-dom';
3 |
4 | export * from './Auth';
5 | export { default as AuthBtn } from './Auth';
6 |
7 | interface AuthorizedProps {
8 | authority?: boolean;
9 | children: JSX.Element;
10 | redirectPath?: string;
11 | }
12 | const AuthPage = (
13 | props: AuthorizedProps = { children: },
14 | ): JSX.Element => {
15 | let navigate = useNavigate();
16 | /** Navigate 重定向 会报错 */
17 | React.useEffect(() => {
18 | if (!props.authority) {
19 | if (props.redirectPath) {
20 | navigate(props.redirectPath, { replace: true });
21 | } else {
22 | navigate('/login', { replace: true });
23 | }
24 | }
25 | }, [props.redirectPath]);
26 |
27 | if (props.authority) {
28 | return props.children;
29 | }
30 | return (
31 | Loading...}>
32 |
33 |
34 | );
35 | };
36 | export default AuthPage;
37 |
--------------------------------------------------------------------------------
/packages/authorized/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig",
3 | "include": ["src/**/*"],
4 | "compilerOptions": {
5 | "baseUrl": "./"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/packages/basic-layouts/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@uiw-admin/basic-layouts",
3 | "version": "6.1.9",
4 | "description": "Basic Layouts",
5 | "author": "Kenny Wong ",
6 | "homepage": "https://github.com/uiwjs/uiw-admin/tree/master/packages/basic-layouts#readme",
7 | "repository": {
8 | "type": "git",
9 | "url": "https://github.com/uiwjs/uiw-admin.git"
10 | },
11 | "license": "MIT",
12 | "main": "lib/index.js",
13 | "module": "esm/index.js",
14 | "files": [
15 | "lib",
16 | "esm",
17 | "src"
18 | ],
19 | "publishConfig": {
20 | "access": "public"
21 | },
22 | "keywords": [
23 | "design",
24 | "uiw",
25 | "uiw-react",
26 | "uiw-admin",
27 | "react.js",
28 | "react",
29 | "react-component",
30 | "component",
31 | "components",
32 | "ui",
33 | "css",
34 | "uikit",
35 | "react-ui",
36 | "framework",
37 | "front-end",
38 | "frontend"
39 | ],
40 | "peerDependencies": {
41 | "react": ">=17.x",
42 | "react-dom": ">=17.x",
43 | "uiw": ">=4.x"
44 | },
45 | "dependencies": {
46 | "@babel/runtime": "~7.21.0",
47 | "@kkt/pro": "^1.0.13",
48 | "@uiw-admin/document-title": "6.1.9",
49 | "classnames": "2.3.1",
50 | "pinyin": "~2.11.2"
51 | },
52 | "devDependencies": {
53 | "@types/classnames": "2.3.1",
54 | "@types/pinyin": "2.10.0",
55 | "@types/react": "~18.0.25",
56 | "@types/react-dom": "~18.0.11",
57 | "react": "18.2.0",
58 | "react-dom": "18.2.0",
59 | "react-router": "^6.8.0",
60 | "react-router-dom": "^6.8.0",
61 | "uiw": "^4.21.26"
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/packages/basic-layouts/src/components/BodyContent/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { KktproRoutesProps } from '@kkt/pro';
3 | import { useLocation, useNavigate, Navigate } from 'react-router-dom';
4 | import { onNavigate } from '../Menu';
5 |
6 | interface ContentProps {
7 | children: React.ReactNode;
8 | }
9 | export default (props: ContentProps) => {
10 | return (
11 |
12 | {props.children}
13 |
14 | );
15 | };
16 | export interface WarpBodyProps {
17 | children: React.ReactNode;
18 | sideItemIndex: undefined | KktproRoutesProps;
19 | }
20 | export const WarpBody = (props: WarpBodyProps) => {
21 | const { sideItemIndex } = props;
22 | const location = useLocation();
23 | const navigate = useNavigate();
24 | if (
25 | sideItemIndex &&
26 | sideItemIndex.index &&
27 | sideItemIndex.path &&
28 | sideItemIndex.path !== '*' &&
29 | sideItemIndex.path !== '/'
30 | ) {
31 | if (sideItemIndex.navigate) {
32 | const result = onNavigate(sideItemIndex as any, navigate, { location });
33 | if (!result) {
34 | return ;
35 | }
36 | }
37 | return (
38 |
39 |
40 |
41 | );
42 | }
43 | return {props.children};
44 | };
45 |
--------------------------------------------------------------------------------
/packages/basic-layouts/src/components/Breadcrumb/index.css:
--------------------------------------------------------------------------------
1 | .w-breadcrumb.uiw-admin-breadcrumb .w-breadcrumb-item {
2 | cursor: pointer;
3 | }
4 |
--------------------------------------------------------------------------------
/packages/basic-layouts/src/components/FullScreen/index.tsx:
--------------------------------------------------------------------------------
1 | import { useState, useMemo, useEffect } from 'react';
2 | import IconBox from '../IconBox';
3 | import { useMain } from '../../hook';
4 |
5 | /**
6 | * 当前是否全屏
7 | */
8 | function isFullScreen() {
9 | let el: any = document;
10 | return (
11 | el.mozFullScreen ||
12 | el.webkitIsFullScreen ||
13 | el.webkitFullScreen ||
14 | el.msFullScreen
15 | );
16 | }
17 |
18 | /**
19 | * 判断当前文档是否能切换到全屏
20 | */
21 | function isFullscreenEnabled() {
22 | let el: any = document;
23 | return (
24 | el.fullscreenEnabled ||
25 | el.mozFullScreenEnabled ||
26 | el.webkitFullscreenEnabled ||
27 | el.msFullscreenEnabled
28 | );
29 | }
30 |
31 | export default () => {
32 | if (!isFullscreenEnabled()) return null;
33 | const [fullscreen, setFullscreen] = useState(false);
34 | if (fullscreen) {
35 | let element: any = document.documentElement;
36 | if (element.requestFullscreen) {
37 | element.requestFullscreen();
38 | } else if (element.webkitRequestFullScreen) {
39 | element.webkitRequestFullScreen();
40 | } else if (element.mozRequestFullScreen) {
41 | element.mozRequestFullScreen();
42 | } else if (element.msRequestFullscreen) {
43 | element.msRequestFullscreen();
44 | }
45 | } else if (isFullScreen()) {
46 | let el: any = document;
47 | if (el.exitFullscreen) {
48 | el.exitFullscreen();
49 | } else if (el.webkitCancelFullScreen) {
50 | el.webkitCancelFullScreen();
51 | } else if (el.mozCancelFullScreen) {
52 | el.mozCancelFullScreen();
53 | } else if (el.msExitFullscreen) {
54 | el.msExitFullscreen();
55 | }
56 | }
57 | const { headerFontColor } = useMain();
58 | const handle = () => {
59 | if (!isFullScreen() && fullscreen) {
60 | setFullscreen(false);
61 | }
62 | };
63 |
64 | useEffect(() => {
65 | window.addEventListener('resize', handle);
66 | return () => {
67 | window.removeEventListener('resize', handle, false);
68 | };
69 | });
70 |
71 | return useMemo(
72 | () => (
73 | setFullscreen(!fullscreen)}
78 | style={{ marginRight: 10 }}
79 | />
80 | ),
81 | [fullscreen],
82 | );
83 | };
84 |
--------------------------------------------------------------------------------
/packages/basic-layouts/src/components/HeaderRightMenu/index.css:
--------------------------------------------------------------------------------
1 | .uiw-global-header-menu {
2 | display: inline-flex;
3 | align-items: center;
4 | cursor: pointer;
5 | position: relative;
6 | }
7 | .uiw-global-header-menu .avatar,
8 | .uiw-global-header-menu img {
9 | height: 30px;
10 | width: 30px;
11 | border-radius:50px;
12 | background-color: antiquewhite;
13 | }
14 | .uiw-global-header-menu .avatar{
15 | line-height: 30px;
16 | text-align: center;
17 | font-weight: bolder;
18 | background-color: rgba(167, 182, 194, 0.3);
19 | }
--------------------------------------------------------------------------------
/packages/basic-layouts/src/components/IconBox/index.css:
--------------------------------------------------------------------------------
1 | .uiw-admin-icons {
2 | width: 34px;
3 | height: 34px;
4 | display: inline-flex;
5 | align-items: center;
6 | justify-content: center;
7 | opacity: .9;
8 | cursor: pointer;
9 | transition: background .5s;
10 | border-radius: 5px;
11 | }
12 | .uiw-admin-icons:hover {
13 | opacity: 1;
14 | background: rgba(199, 199, 199, .3);
15 | }
--------------------------------------------------------------------------------
/packages/basic-layouts/src/components/IconBox/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Icon, IconsName } from 'uiw';
3 | import './index.css';
4 |
5 | export interface IconBoxProps {
6 | type?: IconsName;
7 | style?: React.CSSProperties;
8 | iconSTyle?: React.CSSProperties;
9 | className?: string;
10 | color?: string;
11 | onClick?: () => void;
12 | }
13 |
14 | const IconBox = (props: IconBoxProps) => {
15 | const { type, style, iconSTyle, color, className, onClick } = props;
16 | const cls = [className, 'uiw-admin-icons'].filter(Boolean).join(' ').trim();
17 |
18 | return (
19 |
20 |
onClick?.()}>
21 | {type && }
22 |
23 |
24 | );
25 | };
26 |
27 | export default IconBox;
28 |
--------------------------------------------------------------------------------
/packages/basic-layouts/src/components/LogoHeader/index.tsx:
--------------------------------------------------------------------------------
1 | import React, { useMemo } from 'react';
2 | import { Link } from 'react-router-dom';
3 | import { useMain } from '../../hook';
4 |
5 | interface LogoHeaderProps {
6 | collapsed?: boolean;
7 | projectName?: string;
8 | logo?: string;
9 | onLogoClick?: (
10 | event: React.MouseEvent,
11 | ) => void;
12 | }
13 |
14 | export default (props: LogoHeaderProps = {}) => {
15 | const { headerFontColor, headerLayout } = useMain();
16 | const logo = useMemo(
17 | () =>
18 | props.logo &&
,
19 | [props.logo],
20 | );
21 | const name = useMemo(
22 | () =>
23 | props.projectName && (
24 |
25 | {props.projectName}
26 |
27 | ),
28 | [props.projectName, headerFontColor],
29 | );
30 | const linkProps = useMemo(() => {
31 | const { onLogoClick } = props;
32 | return onLogoClick && typeof onLogoClick === 'function'
33 | ? {
34 | onClick: (event: React.MouseEvent) => {
35 | onLogoClick(event);
36 | event.stopPropagation();
37 | event.preventDefault();
38 | },
39 | }
40 | : {};
41 | }, [props.onLogoClick]);
42 |
43 | return useMemo(
44 | () => (
45 |
52 |
57 | {logo}
58 | {!props.collapsed && name}
59 |
60 |
61 | ),
62 | [props.collapsed],
63 | );
64 | };
65 |
--------------------------------------------------------------------------------
/packages/basic-layouts/src/components/index.ts:
--------------------------------------------------------------------------------
1 | export { default as Breadcrumb } from './Breadcrumb';
2 | export * from './Breadcrumb';
3 |
4 | export { default as BodyContent } from './BodyContent';
5 | export * from './BodyContent';
6 |
7 | export { default as FullScreen } from './FullScreen';
8 | export * from './FullScreen';
9 |
10 | export { default as HeaderRightMenu } from './HeaderRightMenu';
11 | export * from './HeaderRightMenu';
12 |
13 | export { default as LogoHeader } from './LogoHeader';
14 | export * from './LogoHeader';
15 |
16 | export { default as Menu } from './Menu';
17 | export * from './Menu';
18 |
19 | export { default as IconBox } from './IconBox';
20 | export * from './IconBox';
21 |
--------------------------------------------------------------------------------
/packages/basic-layouts/src/hook.ts:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { KktproRoutesProps } from '@kkt/pro';
3 | import { useLocation } from 'react-router-dom';
4 |
5 | import { getSideMenusMap, getMenuList, getCurrentPath } from './utils';
6 | export const MainContext = React.createContext<{
7 | headerLayout?: 'top' | 'default';
8 | headerBackground?: string;
9 | headerFontColor?: string;
10 | }>({
11 | headerLayout: 'top',
12 | headerBackground: '#fff',
13 | headerFontColor: '#000',
14 | });
15 |
16 | export const useMain = () => React.useContext(MainContext);
17 |
18 | export const useSideMenus = (props: { routeData: KktproRoutesProps[] }) => {
19 | const { routeData = [] } = props;
20 | const location = useLocation();
21 |
22 | const sideMenusMap = getSideMenusMap(routeData);
23 |
24 | const listMenus = getMenuList(routeData);
25 |
26 | // 获取当前路由匹配信息
27 | const currentPath = getCurrentPath(listMenus, location.pathname);
28 | const hiddenMainMenu = currentPath?.hiddenMainMenu;
29 | // 获取子路由信息
30 | const ChildMenus = React.useMemo(() => {
31 | const parentPath = sideMenusMap.flat.get(currentPath?.path || '');
32 | if (parentPath && parentPath !== '/') {
33 | return {
34 | routeData: sideMenusMap.sideMenus.get(parentPath) || [],
35 | parentPath,
36 | };
37 | }
38 | return {
39 | routeData,
40 | parentPath,
41 | };
42 | }, [currentPath, routeData, sideMenusMap]);
43 |
44 | const sideItemIndex = React.useMemo(() => {
45 | if (currentPath && currentPath.side) {
46 | const item = ChildMenus.routeData.find((item) => item.index);
47 | if (item) {
48 | return item;
49 | }
50 | }
51 | return undefined;
52 | }, [location.pathname, currentPath]);
53 |
54 | return {
55 | sideItemIndex,
56 | ChildMenus,
57 | sideMenusMap,
58 | hiddenMainMenu,
59 | };
60 | };
61 |
--------------------------------------------------------------------------------
/packages/basic-layouts/src/index.css:
--------------------------------------------------------------------------------
1 | #root > div {
2 | height: 100%;
3 | }
4 | .uiw-admin-global-sider-menu {
5 | box-shadow: 2px 0 6px rgba(0, 21, 41, 0.35);
6 | overflow: auto;
7 | }
8 |
9 | .uiw-admin-global-sider-menu .w-menu-item {
10 | padding: 9px;
11 | }
12 | .uiw-admin-global-sider-menu .w-menu-item.active {
13 | background: rgba(167, 182, 194, 0.3) !important;
14 | border-radius: 7px;
15 | }
16 | .uiw-admin-global-sider-menu .w-menu-item:hover {
17 | background: transparent;
18 | color: #fff;
19 | }
20 |
21 | .uiw-admin-global-sider-menu .w-search-select-search-true input {
22 | height: 34px;
23 | border-radius: 7px;
24 | }
25 |
26 | .w-layout-header.uiw-admin-global-header > * {
27 | vertical-align: middle;
28 | }
29 | .w-layout-header.uiw-admin-global-header {
30 | /* border-bottom: 1px solid #ccc; */
31 | height: 53px;
32 | min-height: 53px;
33 | line-height: 53px;
34 | background-color: #fff;
35 | padding-left: 10px;
36 | padding-right: 20px;
37 | display: flex;
38 | justify-content: space-between;
39 | }
40 | .uiw-admin-global-title,
41 | .uiw-admin-global-title-top {
42 | position: relative;
43 | padding: 0 14px;
44 | overflow: hidden;
45 | cursor: pointer;
46 | transition: all 0.3s;
47 | }
48 | .uiw-admin-global-title-top {
49 | height: 100%;
50 | }
51 |
52 | .uiw-admin-global-title-top a {
53 | height: 100%;
54 | text-decoration: none !important;
55 | }
56 | .uiw-admin-global-title a {
57 | text-decoration: none !important;
58 | }
59 | .uiw-admin-global-title h1,
60 | .uiw-admin-global-title-top h1 {
61 | box-sizing: border-box;
62 | display: inline-block;
63 | margin: 0 12px;
64 | color: #fff;
65 | font-weight: 600;
66 | font-size: 20px;
67 | vertical-align: middle;
68 | animation: fade-in;
69 | animation-duration: 0.3s;
70 | white-space: nowrap;
71 | }
72 | .uiw-admin-global-title a {
73 | display: flex;
74 | align-items: center;
75 | padding-top: 16px;
76 | padding-bottom: 10px;
77 | text-decoration: none;
78 | color: #fff;
79 | font-weight: bold;
80 | }
81 | .uiw-admin-global-title img,
82 | .uiw-admin-global-title-top img {
83 | display: inline-block;
84 | height: 36px;
85 | vertical-align: middle;
86 | }
87 |
88 | .uiw-admin-global-title-top a {
89 | display: flex;
90 | align-items: center;
91 | text-decoration: none !important;
92 | }
93 |
94 | .uiw-admin-global-content {
95 | /* overflow: auto; */
96 | height: 100%;
97 | /* padding: 14px; */
98 | }
99 |
100 | .w-overlay {
101 | z-index: 1000;
102 | }
103 |
104 | .w-notify-warpper {
105 | z-index: 1001;
106 | }
107 | .uiw-admin-nav {
108 | display: inline-flex;
109 | align-items: center;
110 | }
111 |
112 | .w-overlay .w-menu-item {
113 | padding: 9px 8px;
114 | border-radius: 5px;
115 | }
--------------------------------------------------------------------------------
/packages/basic-layouts/src/useLayouts.tsx:
--------------------------------------------------------------------------------
1 | import { useState } from 'react';
2 |
3 | export interface Params {
4 | headerRightvisible: boolean;
5 | }
6 | export interface UseLayoutsProps {
7 | headerRightvisible: boolean;
8 | closeMenu: () => void;
9 | updateStore: (datas: Params) => void;
10 | }
11 |
12 | const useLayouts = () => {
13 | const [state, setState] = useState({
14 | headerRightvisible: false,
15 | });
16 | // 更新store
17 | const updateStore = (datas: Params) => {
18 | setState({
19 | ...state,
20 | ...datas,
21 | });
22 | };
23 |
24 | // 关闭右上角menu菜单
25 | const closeMenu = () => updateStore({ headerRightvisible: false });
26 |
27 | return {
28 | closeMenu,
29 | updateStore,
30 | ...state,
31 | };
32 | };
33 |
34 | export default useLayouts;
35 |
--------------------------------------------------------------------------------
/packages/basic-layouts/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig",
3 | "include": ["src/**/*"],
4 | "compilerOptions": {
5 | "baseUrl": "./"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/packages/components/README.md:
--------------------------------------------------------------------------------
1 | # `components`
2 |
3 | [](https://www.npmjs.com/package/@uiw-admin/components)
4 |
5 | > 业务常用组件
6 |
7 | ## Usage
8 |
9 | ``` ts
10 | import { ProTable, ProForm, ProDrawer, Skeleton } from '@uiw-admin/components';
11 | ```
12 |
13 | ## 已开发的组件
14 |
15 | - ✅ ProTable: 集成搜索表单的Table组件,用于一般页面的查询搜索。
16 | - ✅ ProForm: 基于[uiw from](https://uiwjs.github.io/#/components/form)封装, 更方便的使用表单。
17 | - ✅ ProDrawer: 屏幕边缘滑出的浮层面板,集成权限button按钮。
18 | - ✅ Skeleton: 页面骨架组件,用于整个界面的loading效果,也可调整统一边距。
19 |
20 |
21 |
22 |
23 | ## 贡献者
24 |
25 | 感谢所有的贡献者,欢迎开发者为开源项目贡献力量。
26 |
27 |
28 |
29 |
30 |
31 | ## License
32 |
33 | Licensed under the MIT License.
--------------------------------------------------------------------------------
/packages/components/__tests__/components.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const components = require('..');
4 |
5 | describe('components', () => {
6 | it('needs tests');
7 | });
8 |
--------------------------------------------------------------------------------
/packages/components/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@uiw-admin/components",
3 | "version": "6.1.9",
4 | "description": "业务组件集合",
5 | "author": "xingyuefeng <15262870437@163.com>",
6 | "homepage": "https://github.com/uiwjs/uiw-admin#readme",
7 | "license": "MIT",
8 | "main": "lib/index.js",
9 | "module": "esm/index.js",
10 | "directories": {
11 | "lib": "lib",
12 | "test": "__tests__"
13 | },
14 | "files": [
15 | "lib",
16 | "esm",
17 | "src"
18 | ],
19 | "repository": {
20 | "type": "git",
21 | "url": "git+https://github.com/uiwjs/uiw-admin.git"
22 | },
23 | "keywords": [
24 | "design",
25 | "uiw",
26 | "uiw-react",
27 | "uiw-admin",
28 | "react.js",
29 | "react",
30 | "react-component",
31 | "component",
32 | "components",
33 | "ui",
34 | "css",
35 | "uikit",
36 | "react-ui",
37 | "framework",
38 | "front-end",
39 | "frontend"
40 | ],
41 | "peerDependencies": {
42 | "react": ">=17.x",
43 | "react-dom": ">=17.x",
44 | "uiw": ">=4.x"
45 | },
46 | "dependencies": {
47 | "@babel/runtime": "~7.21.0",
48 | "@uiw-admin/authorized": "6.1.9",
49 | "@uiw-admin/document-title": "6.1.9",
50 | "@uiw-admin/utils": "6.1.9",
51 | "classnames": "2.3.1"
52 | },
53 | "devDependencies": {
54 | "@types/classnames": "2.3.1",
55 | "@types/react": "~18.0.25",
56 | "@types/react-dom": "~18.0.11",
57 | "react": "18.2.0",
58 | "react-dom": "18.2.0",
59 | "react-router": "^6.8.0",
60 | "react-router-dom": "^6.8.0",
61 | "uiw": "^4.21.26"
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/packages/components/src/ProDrawer/index.tsx:
--------------------------------------------------------------------------------
1 | import React, { memo } from 'react';
2 | import { Drawer, Button, DrawerProps, ButtonProps } from 'uiw';
3 | import { AuthBtn, AuthBtnProps } from '@uiw-admin/authorized';
4 | /**
5 | * ProDrawer 组件继承于https://uiwjs.github.io/#/components/drawer
6 | * @param {boolean} visible 显示隐藏
7 | * @param {string} title 标题
8 | * @param {()=>void} onClose 关闭事件
9 | * @param {number} width Drawer宽
10 | * @param {Array<{label?:string,onPress?:()=>void,show?:boolean,loading?:boolean}>} buttons 按钮集合(label:"文本",onPress:点击事件,show:是否展示)
11 | * @param {React.ReactNode} children
12 | * @returns
13 | */
14 |
15 | interface ButtonsProps extends ButtonProps {
16 | label?: string;
17 | show?: boolean;
18 | path?: string;
19 | disabled?: boolean;
20 | }
21 |
22 | interface ProDrawerProps extends DrawerProps {
23 | visible: boolean;
24 | title?: string;
25 | onClose?: any;
26 | width?: number;
27 | buttons?: Array;
28 | children?: React.ReactNode;
29 | }
30 |
31 | // button权限
32 | function BtnAuth({ path, children, ...others }: AuthBtnProps) {
33 | if (path)
34 | return (
35 |
36 | {children}
37 |
38 | );
39 | return <>{children}>;
40 | }
41 |
42 | function ProDrawer(props: ProDrawerProps) {
43 | const {
44 | visible,
45 | title = '',
46 | onClose = null,
47 | width = 800,
48 | buttons = [],
49 | children,
50 | ...others
51 | } = props;
52 | return (
53 |
64 | show && (
65 |
66 |
69 |
70 | ),
71 | )}
72 | {...others}
73 | >
74 | {children}
75 |
76 | );
77 | }
78 |
79 | export default memo(ProDrawer);
80 |
--------------------------------------------------------------------------------
/packages/components/src/ProForm/hooks/store.tsx:
--------------------------------------------------------------------------------
1 | import { useContext, createContext } from 'react';
2 | import { ColProps } from 'uiw';
3 | export const StoreCtx = createContext({});
4 |
5 | export const useStore = () => {
6 | return useContext(StoreCtx);
7 | };
8 |
9 | export const ColPropsContext = createContext({});
10 |
11 | export const useColPropsContext = () => useContext(ColPropsContext);
12 |
--------------------------------------------------------------------------------
/packages/components/src/ProForm/hooks/useForm.tsx:
--------------------------------------------------------------------------------
1 | import { useState } from 'react';
2 | import { UseFormStateProps } from '../type';
3 | import { isObjectEmpty } from '../utils/index';
4 |
5 | const useForm = () => {
6 | // form表单实例
7 | const [formState, setFormState] = useState<{ current: UseFormStateProps }>();
8 |
9 | // 表单验证(同时兼容老api submitvalidate和新api onSubmit )
10 | const submitvalidate = () => formState?.current?.onSubmit() || null;
11 | // 获取表单的值
12 | const getFieldValues = () => formState?.current?.getFieldValues() || {};
13 | // 获取表单错误信息
14 | const getError = () => formState?.current?.getError() || {};
15 |
16 | // 验证并获取表单值
17 | const validateFieldsAndGetValue = () => {
18 | return new Promise(async function (resolve, reject) {
19 | await submitvalidate();
20 | const errors = getError();
21 | if (isObjectEmpty(errors)) {
22 | const value = getFieldValues();
23 | resolve(value);
24 | } else {
25 | reject(errors);
26 | }
27 | });
28 | };
29 |
30 | return {
31 | ...formState?.current,
32 | submitvalidate,
33 | getError,
34 | getFieldValues,
35 | validateFieldsAndGetValue,
36 | // --------------
37 | setFormState,
38 | };
39 | };
40 |
41 | export default useForm;
42 |
--------------------------------------------------------------------------------
/packages/components/src/ProForm/readform.tsx:
--------------------------------------------------------------------------------
1 | import { Descriptions } from 'uiw';
2 | import { ProFormProps } from './type';
3 | import { getReadValue } from './utils/index';
4 |
5 | export default ({
6 | title,
7 | formDatas,
8 | readOnlyProps,
9 | className,
10 | layout,
11 | style,
12 | }: ProFormProps) => {
13 | return (
14 |
22 | {formDatas?.map(
23 | (
24 | {
25 | hide,
26 | label,
27 | widget,
28 | initialValue = '',
29 | option = [],
30 | readSpan = 1,
31 | widgetProps = {},
32 | },
33 | index,
34 | ) => {
35 | return hide ? null : (
36 |
37 | {getReadValue(widget, initialValue, option, widgetProps)}
38 |
39 | );
40 | },
41 | )}
42 |
43 | );
44 | };
45 |
--------------------------------------------------------------------------------
/packages/components/src/ProForm/style/form-item.css:
--------------------------------------------------------------------------------
1 | .w-form-item-center {
2 | display: flex;
3 | align-items: center;
4 | justify-content: flex-end;
5 | }
6 |
7 | .w-switch,
8 | .w-checkbox,
9 | .w-radio
10 | {
11 | height: 30px;
12 | display: inline-flex;
13 | align-items: center;
14 | margin-right: 5px;
15 | }
16 |
17 | .w-proform-label {
18 | position: relative;
19 | padding-left: 7px;
20 | display: inline-block;
21 | }
22 | .w-proform-label::before {
23 | content: '*';
24 | position: absolute;
25 | left: 0;
26 | top: 3px;
27 | transform: translateX(-50%);
28 | color: red;
29 | }
30 |
31 | .uiw-admin-proform .w-form-label {
32 | font-weight: normal;
33 | color: rgba(0, 0, 0, .5);
34 | }
35 | .uiw-admin-proform .w-select {
36 | background-color: transparent;
37 | }
38 |
39 | .uiw-admin-proform > .w-card .w-card-head {
40 | height: 44px;
41 | line-height: 44px;
42 | }
43 | .uiw-admin-proform > .w-descriptions .w-descriptions-title {
44 | height: 44px;
45 | display: flex;
46 | align-items: center;
47 | }
48 | .uiw-admin-proform > .w-collapse .w-collapse-header {
49 | height: 44px;
50 | align-items: center;
51 | font-weight: 500;
52 | }
53 | .uiw-admin-proform > .w-descriptions {
54 | border-top: none;
55 | }
56 | .uiw-admin-proform > .w-descriptions .w-descriptions-title {
57 | width: 100%;
58 | display: table-caption;
59 | box-sizing: border-box;
60 | line-height: 44px;
61 | border-top: 1px solid #dfe2e5;
62 | padding: 0 12px;
63 | }
64 | .uiw-admin-proform-btn {
65 | height: 34px;
66 | min-width: 80px;
67 | }
68 | .uiw-admin-proform-horizontal .w-form {
69 | padding-top: 14px;
70 | }
71 | .uiw-admin-proform-horizontal .w-form-item {
72 | display: flex;
73 | align-items: flex-start;
74 | position: relative;
75 | padding-bottom: 16px;
76 | }
77 | .uiw-admin-proform-horizontal .w-form-item .w-form-label {
78 | margin-right: 14px;
79 | width: 120px;
80 | text-align: right;
81 | position: relative;
82 | display: flex;
83 | align-items: center;
84 | justify-content: flex-end;
85 | }
86 | .uiw-admin-proform-horizontal .w-form-item .w-form-label::after {
87 | content: ':';
88 | position: absolute;
89 | right: 0;
90 | top: 7px;
91 | }
92 | .uiw-admin-proform-horizontal .w-form-item .w-form-row > div {
93 | width: 100%;
94 | }
95 | .uiw-admin-proform-horizontal .w-form-item .w-form-help {
96 | position: absolute;
97 | left: 134px;
98 | bottom: -2px;
99 | }
100 | .uiw-admin-proform-vertical .w-descriptions-vertical .w-descriptions-item-label {
101 | text-align: left;
102 | }
--------------------------------------------------------------------------------
/packages/components/src/ProForm/widgets/CheckBox/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Checkbox } from 'uiw';
3 |
4 | interface FormSelectProps {
5 | option?: HTMLOptionElement[];
6 | }
7 |
8 | const FormCheckBox: React.FC = ({ option, ...others }) => {
9 | return (
10 |
11 | {option &&
12 | option.map((opt) => (
13 |
14 | {opt.label}
15 |
16 | ))}
17 |
18 | );
19 | };
20 |
21 | export default FormCheckBox;
22 |
--------------------------------------------------------------------------------
/packages/components/src/ProForm/widgets/SearchTree/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { SearchTree, SearchTreeProps, TreeData } from 'uiw';
3 |
4 | const FormSearchTree: React.FC<
5 | SearchTreeProps & { option: TreeData[] }
6 | > = ({ option, ...others }) => {
7 | return ;
8 | };
9 |
10 | export default FormSearchTree;
11 |
--------------------------------------------------------------------------------
/packages/components/src/ProForm/widgets/Upload/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { FileInput, Icon, Modal, Button, FileInputListProps } from 'uiw';
3 |
4 | interface FileInputProps extends Omit {
5 | uploadType?: 'card' | 'picture' | 'text';
6 | }
7 |
8 | const Upload = ({
9 | uploadType,
10 | value,
11 | readonly = false,
12 | maxNumber,
13 | ...others
14 | }: FileInputProps) => {
15 | const [visible, setVisible] = React.useState(false);
16 | const [src, setSrc] = React.useState('');
17 |
18 | const renderBtn = () => {
19 | if (readonly) return null;
20 | if (uploadType === 'card') return ;
21 | if (uploadType === 'picture' || uploadType === 'text')
22 | return ;
23 | return null;
24 | };
25 |
26 | return (
27 |
28 | {
34 | setSrc(file?.dataURL);
35 | setVisible(true);
36 | }}
37 | {...others}
38 | >
39 | {renderBtn()}
40 |
41 | {/* 预览 */}
42 | setVisible(false)}
45 | width={600}
46 | confirmButtonProps={{ style: { display: 'none' } }}
47 | >
48 |
54 |
55 |
56 | );
57 | };
58 |
59 | export default Upload;
60 |
--------------------------------------------------------------------------------
/packages/components/src/ProForm/widgets/index.tsx:
--------------------------------------------------------------------------------
1 | import { FormFields, FormItemsProps } from '../type';
2 | import {
3 | Input,
4 | InputNumber,
5 | Switch,
6 | Textarea,
7 | DateInput,
8 | TimePicker,
9 | MonthPicker,
10 | SearchSelect,
11 | Rate,
12 | } from 'uiw';
13 | import Radio from '../../ProTable/widgets/Radio';
14 | import Select from '../../ProTable/widgets/Select';
15 | import CheckBox from './CheckBox';
16 | import SelectMultiple from './SelectMultiple';
17 | import Upload from './Upload';
18 | import SearchTree from './SearchTree';
19 | import { isRequired } from '../utils';
20 |
21 | /**
22 | *
23 | * @param readOnly 是否是只读模式 boolean
24 | * @param formDatas 表单项 FormItemsProps[]
25 | * @returns fields Record>
26 | */
27 | export function getFormFields(
28 | readOnly?: boolean,
29 | formDatas: FormItemsProps[] = [],
30 | customWidgetsList: FormFields = {},
31 | ) {
32 | const widgetsList: FormFields = {
33 | input: Input,
34 | inputNumber: InputNumber,
35 | radio: Radio,
36 | checkbox: CheckBox,
37 | switch: Switch,
38 | select: Select,
39 | searchSelect: SearchSelect,
40 | selectMultiple: SelectMultiple,
41 | textarea: Textarea,
42 | dateInput: DateInput,
43 | timePicker: TimePicker,
44 | monthPicker: MonthPicker,
45 | upload: Upload,
46 | rate: Rate,
47 | searchTree: SearchTree,
48 | ...customWidgetsList,
49 | };
50 | const fields: FormFields = {};
51 | formDatas.forEach((col) => {
52 | if (!readOnly) delete col.readSpan;
53 | if (col) {
54 | const {
55 | hide = false,
56 | widgetProps,
57 | key,
58 | widget,
59 | label,
60 | initialValue,
61 | required,
62 | ...otherProps
63 | } = col;
64 | if (!hide) {
65 | const name = key;
66 | const Widget = widgetsList[widget];
67 | const is = isRequired(otherProps?.rules || []);
68 | fields[name] = {
69 | label: is ? {label} : label,
70 | children: ,
71 | ...otherProps,
72 | initialValue,
73 | };
74 | }
75 | }
76 | });
77 | return fields;
78 | }
79 |
--------------------------------------------------------------------------------
/packages/components/src/ProTable/hooks.ts:
--------------------------------------------------------------------------------
1 | import { useContext, createContext } from 'react';
2 |
3 | export const StoreCtx = createContext({});
4 |
5 | export const useStore = () => {
6 | return useContext(StoreCtx);
7 | };
8 |
--------------------------------------------------------------------------------
/packages/components/src/ProTable/index.css:
--------------------------------------------------------------------------------
1 | .is-need-table-header {
2 | border-top: 1px solid #e8e8e8;
3 | }
4 | .is-need-table-header table thead {
5 | display: none;
6 | }
7 | .table-parent-uiw-admin table tr td {
8 | background-color: transparent !important;
9 | background: transparent !important;
10 | }
11 |
12 | .uiw-admin-protable table tr td {
13 | padding: 8px;
14 | }
15 |
16 | .uiw-protable-form .w-form-label {
17 | font-weight: normal;
18 | color: rgba(0, 0, 0, 0.7);
19 | }
20 |
21 | .uiw-protable-form .w-select {
22 | background-color: transparent;
23 | }
24 |
25 | .uiw-admin-protable .w-table > table {
26 | border-top: 1px solid #e8e8e8;
27 | }
--------------------------------------------------------------------------------
/packages/components/src/ProTable/style/index.less:
--------------------------------------------------------------------------------
1 | .pro-table {
2 | }
3 |
--------------------------------------------------------------------------------
/packages/components/src/ProTable/useSelections.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-unused-vars */
2 | import { useMemo, useState } from 'react';
3 |
4 | export type UseSelections = {
5 | selected: T[];
6 | noneSelected: Boolean;
7 | allSelected: Boolean;
8 | partiallySelected: Boolean;
9 | setSelected: (value: T[]) => void;
10 | isSelected: (value: T) => boolean;
11 | select: (item: T) => void;
12 | unSelect: (item: T) => void;
13 | toggle: (value: T) => void;
14 | selectAll: () => void;
15 | unSelectAll: () => void;
16 | toggleAll: () => void;
17 | };
18 |
19 | export default function useSelections(
20 | items: T[],
21 | defaultSelected: T[] = [],
22 | isSingle: Boolean = false,
23 | ): UseSelections {
24 | const [selected, setSelected] = useState(defaultSelected);
25 |
26 | const selectedSet = useMemo(() => new Set(selected), [selected]);
27 |
28 | const isSelected = (item: T) => selectedSet.has(item);
29 |
30 | const unSelectAll = () => {
31 | items.forEach((o) => {
32 | selectedSet.delete(o);
33 | });
34 | setSelected(Array.from(selectedSet));
35 | };
36 |
37 | const select = (item: T) => {
38 | if (isSingle) {
39 | unSelectAll();
40 | }
41 | selectedSet.add(item);
42 | return setSelected(Array.from(selectedSet));
43 | };
44 |
45 | const unSelect = (item: T) => {
46 | selectedSet.delete(item);
47 | return setSelected(Array.from(selectedSet));
48 | };
49 |
50 | const toggle = (item: T) => {
51 | if (isSelected(item)) {
52 | unSelect(item);
53 | } else {
54 | select(item);
55 | }
56 | };
57 |
58 | const selectAll = () => {
59 | items.forEach((o) => {
60 | selectedSet.add(o);
61 | });
62 | setSelected(Array.from(selectedSet));
63 | };
64 |
65 | const noneSelected = useMemo(
66 | () => items.every((o) => !selectedSet.has(o)),
67 | [items, selectedSet],
68 | );
69 |
70 | const allSelected = useMemo(
71 | () => items.every((o) => selectedSet.has(o)) && !noneSelected,
72 | [items, selectedSet, noneSelected],
73 | );
74 |
75 | const partiallySelected = useMemo(
76 | () => !noneSelected && !allSelected,
77 | [noneSelected, allSelected],
78 | );
79 |
80 | const toggleAll = () => (allSelected ? unSelectAll() : selectAll());
81 |
82 | return {
83 | selected,
84 | noneSelected,
85 | allSelected,
86 | partiallySelected,
87 | setSelected,
88 | isSelected,
89 | select: select,
90 | unSelect: unSelect,
91 | toggle: toggle,
92 | selectAll: selectAll,
93 | unSelectAll: unSelectAll,
94 | toggleAll: toggleAll,
95 | };
96 | }
97 |
--------------------------------------------------------------------------------
/packages/components/src/ProTable/useTable.ts:
--------------------------------------------------------------------------------
1 | import { useState, MutableRefObject } from 'react';
2 | import { Params, useTableData, stateParams } from './types';
3 | import { FormRefType } from 'uiw';
4 |
5 | const useTable = (key: string, params: Params = {}): useTableData => {
6 | const { formatData, query, mutationOptions, requestOptions } = params;
7 |
8 | // 表单组件实例
9 | const [form, setForm] = useState>();
10 |
11 | const [state, setState] = useState({
12 | // 当前页码
13 | pageIndex: 1,
14 | // 总页数
15 | total: 1,
16 | // 当前table数据源
17 | data: [],
18 | // 表单值
19 | searchValues: {},
20 | // 加载状态
21 | loading: false,
22 | // 选择框属性
23 | setPageIndex: () => null,
24 | mutate: () => null,
25 | selection: {
26 | selected: [],
27 | noneSelected: false,
28 | allSelected: false,
29 | partiallySelected: false,
30 | setSelected: () => null,
31 | isSelected: () => null,
32 | select: () => null,
33 | unSelect: () => null,
34 | toggle: () => null,
35 | selectAll: () => null,
36 | unSelectAll: () => null,
37 | toggleAll: () => null,
38 | },
39 | });
40 |
41 | // 更新store
42 | const updateStore = (datas: stateParams) => {
43 | setState({
44 | ...state,
45 | ...datas,
46 | });
47 | };
48 |
49 | // 更新form
50 | const updateForm = (form: any) => {
51 | setForm(form);
52 | };
53 | // 重置
54 | const onReset = async () => {
55 | await form?.current.resetForm();
56 | onSearch();
57 | };
58 | // 刷新当前页数据
59 | const onRefersh = async () => {
60 | state.mutate();
61 | };
62 | // 点击查询
63 | const onSearch = async () => {
64 | // 需要表单存在
65 | if (form) {
66 | await form.current.onSubmit();
67 | // @ts-ignore
68 | const isNoError = form.current.getError();
69 | if (Object.keys(isNoError).length === 0) {
70 | await state.setPageIndex(1);
71 | state.mutate();
72 | }
73 | } else {
74 | await state.setPageIndex(1);
75 | state.mutate();
76 | }
77 | };
78 |
79 | return {
80 | key,
81 | // 重置
82 | onReset,
83 | // 刷新当前页数据
84 | onRefersh,
85 | // 点击查询
86 | onSearch,
87 | formatData,
88 | query,
89 | updateStore,
90 | mutationOptions,
91 | form,
92 | requestOptions,
93 | updateForm,
94 | ...state,
95 | };
96 | };
97 |
98 | export default useTable;
99 |
--------------------------------------------------------------------------------
/packages/components/src/ProTable/widgets/Radio.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | import { Radio, RadioGroup } from 'uiw';
3 |
4 | interface FormSelectProps {
5 | option?: HTMLOptionElement[];
6 | disabled?: boolean;
7 | }
8 |
9 | const FormRadio: React.FC = ({
10 | disabled,
11 | option,
12 | ...others
13 | }) => {
14 | const [allDisabled, setAllDisabled] = useState(false);
15 |
16 | // 全部枚举设为disabled
17 |
18 | useEffect(() => {
19 | setAllDisabled(disabled || false);
20 | }, [disabled]);
21 |
22 | return (
23 |
24 | {option &&
25 | option.map((opt) => (
26 |
31 | {opt.label}
32 |
33 | ))}
34 |
35 | );
36 | };
37 |
38 | export default FormRadio;
39 |
--------------------------------------------------------------------------------
/packages/components/src/ProTable/widgets/SearchTree.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { SearchTree } from 'uiw';
3 | import { TreeData } from '@uiw/react-tree';
4 |
5 | interface SearchTreeProps {
6 | option?: TreeData[];
7 | }
8 |
9 | const SearchTreePro: React.FC = ({ option, ...others }) => {
10 | return ;
11 | };
12 |
13 | export default SearchTreePro;
14 |
--------------------------------------------------------------------------------
/packages/components/src/ProTable/widgets/Select.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Select } from 'uiw';
3 |
4 | interface FormSelectProps {
5 | option?: HTMLOptionElement[];
6 | }
7 |
8 | const FormSelect: React.FC = ({ option, ...others }) => {
9 | return (
10 |
19 | );
20 | };
21 |
22 | export default FormSelect;
23 |
--------------------------------------------------------------------------------
/packages/components/src/Skeleton/README.md:
--------------------------------------------------------------------------------
1 | ## 页面骨架组件
2 |
3 | 页面骨架组件,用于整个界面的loading效果,也可调整统一边距。
4 |
5 | ## 用例
6 |
7 | ```jsx mdx:preview
8 | import { Skeleton } from '@uiw-admin/components'
9 | import React from 'react'
10 |
11 | const Demo = () => (
12 |
13 | children
14 |
15 | )
16 |
17 | export default Demo
18 | ```
19 |
20 | ## Props
21 | | 参数 | 说明 | 类型 | 默认值 |
22 | | ------- | ------------ | ------- | ------ |
23 | | loading | 页面加载状态 | Boolean | false |
24 |
25 | > 更多属性文档请参考 [Uiw Loader](https://uiwjs.github.io/#/components/loader)
26 |
27 |
28 | ## 贡献者
29 |
30 | 感谢所有的贡献者,欢迎开发者为开源项目贡献力量。
31 |
32 |
33 |
34 |
35 |
36 | ## License
37 |
38 | Licensed under the MIT License.
--------------------------------------------------------------------------------
/packages/components/src/Skeleton/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Loader } from 'uiw';
3 |
4 | interface SkeletonProps {
5 | children: React.ReactNode;
6 | loading?: boolean;
7 | style?: React.CSSProperties
8 | }
9 |
10 | const Skeleton: React.FC = ({ children, style, loading = false, ...others }) => {
11 | return (
12 |
19 | <>{children}>
20 |
21 | );
22 | };
23 |
24 | export default Skeleton;
25 |
--------------------------------------------------------------------------------
/packages/components/src/form/interface.ts:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {
3 | FormProps,
4 | FormFieldsProps,
5 | ColProps,
6 | ButtonProps,
7 | FormChildrenProps,
8 | } from 'uiw';
9 |
10 | export type Rule =
11 | | ((value: any) => string | undefined)
12 | | Record;
13 |
14 | export interface FormButtonProps extends ButtonProps {
15 | label?: string;
16 | }
17 | export interface FormFieldsNewProps
18 | extends Omit, 'validator'> {
19 | rules?: Rule[];
20 | colProps?: ColProps;
21 | }
22 |
23 | export interface ComFormProps extends FormProps {
24 | fields?: Record>;
25 | }
26 |
27 | export interface FormFieldsNewProps
28 | extends Omit, 'validator'> {
29 | rules?: Rule[];
30 | }
31 |
32 | export interface ComFormProps extends FormProps {
33 | fields?: Record>;
34 | colProps?: ColProps;
35 | buttonGroup?: (
36 | | Omit
37 | | ((childProps: FormChildrenProps) => Omit)
38 | )[];
39 | buttonGroupClassName?: string;
40 | buttonGroupStyle?: React.CSSProperties;
41 |
42 | /** 老的API **/
43 | showSaveButton?: boolean;
44 | showResetButton?: boolean;
45 | saveButtonProps?: FormButtonProps;
46 | resetButtonProps?: FormButtonProps;
47 | }
48 |
--------------------------------------------------------------------------------
/packages/components/src/form/utils/index.ts:
--------------------------------------------------------------------------------
1 | import { Rule, ComFormProps } from '../interface';
2 | /**
3 | * 1. 必填 空字符/空数组/null/undefined/{}
4 | *
5 | * **/
6 | const validatorEmpty = (value: unknown) => {
7 | if (typeof value === 'number') {
8 | return true;
9 | }
10 | if (typeof value === 'string') {
11 | return !!value;
12 | }
13 | if (Array.isArray(value)) {
14 | return !!value.length;
15 | }
16 | if (typeof value === 'function') {
17 | return true;
18 | }
19 | if (typeof value === 'boolean') {
20 | return true;
21 | }
22 | if (Object.prototype.toString.call(value) === '[object Object]') {
23 | return !!Object.keys(value as object).length;
24 | }
25 | return !!value;
26 | };
27 |
28 | export const validator = (values: any, rules: Record) => {
29 | const error: Record = {};
30 | Object.entries(rules).forEach(([key, ruleItems]) => {
31 | if (ruleItems) {
32 | const value = values[key];
33 | const fileRulesError = ruleItems
34 | .map((rule) => {
35 | if (typeof rule === 'function') {
36 | return rule(value);
37 | }
38 | if (rule && typeof rule === 'object') {
39 | if (rule.required && !validatorEmpty(value)) {
40 | return rule.message;
41 | }
42 | if (rule.pattern instanceof RegExp) {
43 | return rule.pattern.test(value);
44 | }
45 | }
46 | return false;
47 | })
48 | .filter(Boolean);
49 | if (fileRulesError.length) {
50 | error[key] = fileRulesError;
51 | }
52 | }
53 | });
54 | return error;
55 | };
56 |
57 | export const getRules = (fields: ComFormProps['fields']) => {
58 | const validatorrules: Record = {};
59 | Object.entries(fields || {}).map(([key, item]) => {
60 | if (item.rules) {
61 | validatorrules[key] = item.rules;
62 | }
63 | });
64 | return validatorrules;
65 | };
66 |
--------------------------------------------------------------------------------
/packages/components/src/index.tsx:
--------------------------------------------------------------------------------
1 | export { default as ProTable } from './ProTable';
2 | export * from './ProTable';
3 | export { default as useTable } from './ProTable/useTable';
4 | export * from './ProTable/useTable';
5 | export { default as Skeleton } from './Skeleton';
6 | export * from './Skeleton';
7 | export { default as ProDrawer } from './ProDrawer';
8 | export * from './ProDrawer';
9 | export { default as ProForm } from './ProForm';
10 | export * from './ProForm';
11 | export { default as useForm } from './ProForm/hooks/useForm';
12 |
13 | export * from './form';
14 | export { default as Form } from './form';
15 |
--------------------------------------------------------------------------------
/packages/components/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig",
3 | "include": ["src/**/*"],
4 | "compilerOptions": {
5 | "baseUrl": "./"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/packages/config/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@uiw-admin/config",
3 | "version": "6.1.9",
4 | "description": "config 全局配置",
5 | "author": "Kenny Wong ",
6 | "homepage": "https://github.com/uiwjs/uiw-admin/tree/master/packages/models#readme",
7 | "license": "MIT",
8 | "main": "lib/index.js",
9 | "module": "esm/index.js",
10 | "files": [
11 | "lib",
12 | "esm",
13 | "src"
14 | ],
15 | "publishConfig": {
16 | "access": "public"
17 | },
18 | "keywords": [
19 | "design",
20 | "uiw",
21 | "uiw-react",
22 | "uiw-admin",
23 | "react.js",
24 | "react",
25 | "react-component",
26 | "component",
27 | "components",
28 | "ui",
29 | "css",
30 | "uikit",
31 | "react-ui",
32 | "framework",
33 | "front-end",
34 | "frontend"
35 | ],
36 | "repository": {
37 | "type": "git",
38 | "url": "git+https://github.com/uiwjs/uiw-admin.git"
39 | },
40 | "scripts": {
41 | "test": "echo \"Error: run tests from root\" && exit 1"
42 | },
43 | "dependencies": {
44 | "@kkt/less-modules": "~7.2.0",
45 | "@kkt/raw-modules": "~7.2.0",
46 | "@kkt/scope-plugin-options": "~7.2.0",
47 | "@uiw-admin/plugins": "6.1.9",
48 | "eslint-config-uiw-admin": "6.1.9"
49 | },
50 | "devDependencies": {
51 | "kkt": "^7.2.0"
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/packages/config/src/uitls.ts:
--------------------------------------------------------------------------------
1 | export const transformationDefineString = (obj: Record) => {
2 | const result: Record = {};
3 | Object.entries(obj).forEach(([key, value]) => {
4 | result[key] = JSON.stringify(value);
5 | });
6 | return result;
7 | };
8 |
9 | export const getFunDefault = (path?: string) => {
10 | if (path) {
11 | const fun = require(path);
12 | return fun.default || fun;
13 | }
14 | return () => {};
15 | };
16 |
--------------------------------------------------------------------------------
/packages/config/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig",
3 | "include": ["src/**/*"],
4 | "compilerOptions": {
5 | "baseUrl": "./"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/packages/document-title/README.md:
--------------------------------------------------------------------------------
1 | # 设置页面标题
2 |
3 | [](https://www.npmjs.com/package/@uiw-admin/document-title)
4 |
5 |
6 | 简化设置页面标题,建议在项目入口设置
7 |
8 | ## 何时使用
9 |
10 | 需要设置页面标题使用
11 |
12 | ## 安装
13 |
14 | ```bash
15 | npm i @uiw-admin/document-title --save # yarn add @uiw-admin/document-title
16 | ```
17 |
18 | ## 案例1
19 |
20 | ```jsx
21 | import React from 'react';
22 | import DocumentTitle from '@uiw-admin/document-title';
23 |
24 | const Home = ()=>{
25 | return (
26 |
27 | Home, sweet home.
28 |
29 | )
30 | }
31 |
32 | export default Home
33 |
34 | ```
35 |
36 | ## 案例2
37 |
38 | ```jsx
39 | import React from 'react';
40 | import DocumentTitle from '@uiw-admin/document-title';
41 |
42 | const Home = ()=>{
43 | return (
44 |
45 |
46 | Home, sweet home.
47 | )
48 | }
49 |
50 | export default Home
51 |
52 | ```
53 |
54 | ## 预览
55 |
56 | 
57 |
58 | ## 贡献者
59 |
60 | 感谢所有的贡献者,欢迎开发者为开源项目贡献力量。
61 |
62 |
63 |
64 |
65 |
66 | ## License
67 |
68 | Licensed under the MIT License.
--------------------------------------------------------------------------------
/packages/document-title/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@uiw-admin/document-title",
3 | "version": "6.1.9",
4 | "description": "Document Title",
5 | "author": "Kenny Wong ",
6 | "homepage": "https://github.com/uiwjs/uiw-admin/tree/master/packages/document-title#readme",
7 | "repository": {
8 | "type": "git",
9 | "url": "https://github.com/uiwjs/uiw-admin.git"
10 | },
11 | "license": "MIT",
12 | "main": "lib/index.js",
13 | "module": "esm/index.js",
14 | "files": [
15 | "lib",
16 | "esm",
17 | "src"
18 | ],
19 | "publishConfig": {
20 | "access": "public"
21 | },
22 | "keywords": [
23 | "design",
24 | "uiw",
25 | "uiw-react",
26 | "uiw-admin",
27 | "react.js",
28 | "react",
29 | "react-component",
30 | "component",
31 | "components",
32 | "ui",
33 | "css",
34 | "uikit",
35 | "react-ui",
36 | "framework",
37 | "front-end",
38 | "frontend"
39 | ],
40 | "peerDependencies": {
41 | "@babel/runtime": ">=7.10.0",
42 | "react": ">=17.x",
43 | "react-dom": ">=17.x"
44 | },
45 | "devDependencies": {
46 | "@babel/runtime": "~7.21.0",
47 | "@types/react": "~18.0.25",
48 | "@types/react-dom": "~18.0.11",
49 | "react": "18.2.0",
50 | "react-dom": "18.2.0"
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/packages/document-title/src/index.tsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, Fragment } from 'react';
2 |
3 | export interface DocumentTitleProps {
4 | title?: string | null | undefined;
5 | children?: React.ReactNode;
6 | }
7 |
8 | function DocumentTitle(props: DocumentTitleProps): JSX.Element {
9 | useEffect(() => {
10 | document.title = props.title || '';
11 | }, [props.title]);
12 | return (
13 |
14 | {React.Children.toArray(props.children).map((child) => {
15 | if (!React.isValidElement(child)) return null;
16 | return React.cloneElement(child, { ...(child.props || {}) });
17 | })}
18 |
19 | );
20 | }
21 |
22 | export default DocumentTitle;
23 |
--------------------------------------------------------------------------------
/packages/document-title/tsconfig copy.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig",
3 | "include": ["src/**/*"],
4 | "compilerOptions": {
5 | "baseUrl": "./"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/packages/document-title/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig",
3 | "include": ["src/**/*"],
4 | "compilerOptions": {
5 | "baseUrl": "./"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/packages/exceptions/README.md:
--------------------------------------------------------------------------------
1 | # 公共异常组件
2 |
3 | [](https://www.npmjs.com/package/@uiw-admin/exceptions)
4 |
5 | > 1. 403 页面
6 | > 2. 404 页面
7 | > 3. 500 页面
8 |
9 | ## 安装
10 |
11 | ```bash
12 | npm i @uiw-admin/exceptions --save # yarn add @uiw-admin/exceptions
13 | ```
14 |
15 | ## 403页面预览
16 |
17 | ```jsx mdx:preview
18 | import { Exceptions403 } from '@uiw-admin/exceptions'
19 | import React from 'react'
20 |
21 | const Demo = () =>
22 |
23 | export default Demo
24 | ```
25 |
26 | ## 404页面预览
27 |
28 | ```jsx mdx:preview
29 | import { Exceptions404 } from '@uiw-admin/exceptions'
30 | import React from 'react'
31 |
32 | const Demo = () =>
33 |
34 | export default Demo
35 | ```
36 |
37 | ## 500页面预览
38 |
39 | ```jsx mdx:preview
40 | import { Exceptions500 } from '@uiw-admin/exceptions'
41 | import React from 'react'
42 |
43 | const Demo = () =>
44 |
45 | export default Demo
46 | ```
47 |
48 | ### ExceptionsProps
49 |
50 | | 参数 | 说明 | 类型 | 默认值 |
51 | | :------ | :------ | :------ | :------ |
52 | | path | 按钮跳转链接 | `string` | `/home` |
53 | | btnText | 按钮文字 | `string` | `返回首页` |
54 |
55 | ## 贡献者
56 |
57 | 感谢所有的贡献者,欢迎开发者为开源项目贡献力量。
58 |
59 |
60 |
61 |
62 |
63 | ## License
64 |
65 | Licensed under the MIT License.
--------------------------------------------------------------------------------
/packages/exceptions/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@uiw-admin/exceptions",
3 | "version": "6.1.9",
4 | "description": "异常组件",
5 | "author": "Kenny Wong ",
6 | "homepage": "https://github.com/uiwjs/uiw-admin/tree/master/packages/Exceptions#readme",
7 | "license": "MIT",
8 | "main": "lib/index.js",
9 | "module": "esm/index.js",
10 | "files": [
11 | "lib",
12 | "esm",
13 | "src"
14 | ],
15 | "publishConfig": {
16 | "access": "public"
17 | },
18 | "keywords": [
19 | "design",
20 | "uiw",
21 | "uiw-react",
22 | "uiw-admin",
23 | "react.js",
24 | "react",
25 | "react-component",
26 | "component",
27 | "components",
28 | "ui",
29 | "css",
30 | "uikit",
31 | "react-ui",
32 | "framework",
33 | "front-end",
34 | "frontend"
35 | ],
36 | "repository": {
37 | "type": "git",
38 | "url": "git+https://github.com/uiwjs/uiw-admin.git"
39 | },
40 | "peerDependencies": {
41 | "react": ">=17.x",
42 | "react-dom": ">=17.x",
43 | "uiw": ">=4.x"
44 | },
45 | "dependencies": {
46 | "@babel/runtime": "~7.20.0"
47 | },
48 | "devDependencies": {
49 | "@types/classnames": "2.3.1",
50 | "@types/react": "~18.0.25",
51 | "@types/react-dom": "~18.0.11",
52 | "react": "18.2.0",
53 | "react-dom": "18.2.0",
54 | "react-router": "^6.8.0",
55 | "react-router-dom": "^6.8.0",
56 | "uiw": "^4.21.26"
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/packages/exceptions/src/Exceptions/403.tsx:
--------------------------------------------------------------------------------
1 | import { Button } from 'uiw';
2 | import './styles/index.css';
3 | import { useNavigate } from 'react-router';
4 | import { ExceptionsProps } from '../index';
5 |
6 | const Exception403 = ({
7 | path = '/home',
8 | btnText = '返回首页',
9 | }: ExceptionsProps) => {
10 | const navigate = useNavigate();
11 | return (
12 |
13 |
16 |
17 |
403
18 | 抱歉,你无权访问该页面
19 |
25 |
26 |
27 | );
28 | };
29 | export default Exception403;
30 |
--------------------------------------------------------------------------------
/packages/exceptions/src/Exceptions/404.tsx:
--------------------------------------------------------------------------------
1 | import { Button } from 'uiw';
2 | import { useNavigate } from 'react-router';
3 | import './styles/index.css';
4 | import { ExceptionsProps } from '../index';
5 |
6 | const Exception404 = ({
7 | path = '/home',
8 | btnText = '返回首页',
9 | }: ExceptionsProps) => {
10 | const navigate = useNavigate();
11 |
12 | return (
13 |
14 |
17 |
18 |
404
19 | 抱歉,你访问的页面不存在
20 |
26 |
27 |
28 | );
29 | };
30 | export default Exception404;
31 |
--------------------------------------------------------------------------------
/packages/exceptions/src/Exceptions/500.tsx:
--------------------------------------------------------------------------------
1 | import { Button } from 'uiw';
2 | import './styles/index.css';
3 | import { useNavigate } from 'react-router';
4 | import { ExceptionsProps } from '../index';
5 |
6 | const Exception500 = ({
7 | path = '/home',
8 | btnText = '返回首页',
9 | }: ExceptionsProps) => {
10 | const navigate = useNavigate();
11 | return (
12 |
13 |
16 |
17 |
500
18 | 抱歉,服务器出错了
19 |
25 |
26 |
27 | );
28 | };
29 | export default Exception500;
30 |
--------------------------------------------------------------------------------
/packages/exceptions/src/Exceptions/styles/index.css:
--------------------------------------------------------------------------------
1 | .exceptions {
2 | min-height: 500px;
3 | height: 80%;
4 | display: flex;
5 | }
6 | .exceptions .contents {
7 | flex: auto;
8 | align-items: flex-start;
9 | display: flex;
10 | flex-direction: column;
11 | justify-content: center;
12 | }
13 | .exceptions .contents h1 {
14 | color: #434e59;
15 | font-size: 72px;
16 | font-weight: bold;
17 | line-height: 72px;
18 | margin-bottom: 24px;
19 | }
20 | .exceptions .contents h2 {
21 | color: rgba(0, 0, 0, 0.45);
22 | font-size: 20px;
23 | line-height: 28px;
24 | margin-bottom: 16px;
25 | }
26 | .exceptions .contentimgs {
27 | flex: 0 0 62.5%;
28 | width: 62.5%;
29 | padding-right: 152px;
30 | display: flex;
31 | align-items: center;
32 | justify-content: flex-end;
33 | zoom: 1;
34 | }
35 | .exceptions .contentimgs .imgscontent {
36 | height: 360px;
37 | width: 100%;
38 | max-width: 430px;
39 | float: right;
40 | background-repeat: no-repeat;
41 | background-position: 50% 50%;
42 | background-size: contain;
43 | }
44 | .exceptions .contentimgs .imgs404 {
45 | background-image: url('./../asset/404.svg');
46 | }
47 | .exceptions .contentimgs .imgs403 {
48 | background-image: url('./../asset/403.svg');
49 | }
50 | .exceptions .contentimgs .imgs500 {
51 | background-image: url('./../asset/500.svg');
52 | }
53 |
--------------------------------------------------------------------------------
/packages/exceptions/src/index.ts:
--------------------------------------------------------------------------------
1 | export { default as Exceptions404 } from './Exceptions/404';
2 | export { default as Exceptions403 } from './Exceptions/403';
3 | export { default as Exceptions500 } from './Exceptions/500';
4 |
5 | export interface ExceptionsProps {
6 | /** 按钮跳转链接,默认跳转 /home */
7 | path?: string;
8 | /** 按钮文字 */
9 | btnText?: string;
10 | }
11 |
--------------------------------------------------------------------------------
/packages/exceptions/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig",
3 | "include": ["src/**/*"],
4 | "compilerOptions": {
5 | "baseUrl": "./"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/packages/layout-tabs/README.md:
--------------------------------------------------------------------------------
1 | # tab 选项卡布局
2 |
3 | [](https://www.npmjs.com/package/@uiw-admin/layout-tabs)
4 |
5 | 项目打开过的菜单在头部进行tab选项卡展示
6 |
7 | ## 何时使用
8 |
9 | 页面菜单需要tab选项卡切换功能时
10 |
11 | ## 安装
12 |
13 | ```bash
14 | npm i @uiw-admin/layout-tabs --save # yarn add @uiw-admin/layout-tabs
15 | ```
16 |
17 | ## 配合使用 `BasicLayout` 组件使用
18 |
19 | ```jsx mdx:preview
20 | import React from 'react'
21 | import BasicLayout from '@uiw-admin/basic-layouts'
22 | import LayoutTabs from "@uiw-admin/layout-tabs"
23 | const routerArrs = [
24 | {
25 | path: "/components/authorized",
26 | name: "权限组件",
27 | icon: 'appstore',
28 | element: 测试
,
29 | },
30 | {
31 | path: "/components/basic-layouts",
32 | name: "页面布局",
33 | icon: 'appstore',
34 | element: 测试2
,
35 | },
36 | {
37 | path: "/components/layout-tabs",
38 | name: "选项卡",
39 | icon: 'appstore',
40 | element: 测试2
,
41 | }
42 | ]
43 |
44 | function BasicLayoutScreen() {
45 | return (
46 |
47 |
48 |
49 |
50 |
51 | )
52 | }
53 | export default BasicLayoutScreen
54 |
55 | ```
56 |
57 | ## 参数
58 |
59 | ```ts
60 | import { KktproRoutesProps } from '@kkt/pro';
61 |
62 | interface LayoutTabsProps {
63 | /** 子集路由 */
64 | routes: KktproRoutesProps[]
65 | }
66 |
67 | ```
68 | ## 贡献者
69 |
70 | 感谢所有的贡献者,欢迎开发者为开源项目贡献力量。
71 |
72 |
73 |
74 |
75 |
76 | ## License
77 |
78 | Licensed under the MIT License.
--------------------------------------------------------------------------------
/packages/layout-tabs/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@uiw-admin/layout-tabs",
3 | "version": "6.1.9",
4 | "description": "layout tabs",
5 | "author": "Kenny Wong ",
6 | "homepage": "https://github.com/uiwjs/uiw-admin/tree/master/packages/layout-tabs#readme",
7 | "license": "MIT",
8 | "main": "lib/index.js",
9 | "module": "esm/index.js",
10 | "files": [
11 | "lib",
12 | "esm",
13 | "src"
14 | ],
15 | "publishConfig": {
16 | "access": "public"
17 | },
18 | "keywords": [
19 | "design",
20 | "uiw",
21 | "uiw-react",
22 | "uiw-admin",
23 | "react.js",
24 | "react",
25 | "react-component",
26 | "component",
27 | "components",
28 | "ui",
29 | "css",
30 | "uikit",
31 | "react-ui",
32 | "framework",
33 | "front-end",
34 | "frontend"
35 | ],
36 | "repository": {
37 | "type": "git",
38 | "url": "git+https://github.com/uiwjs/uiw-admin.git"
39 | },
40 | "scripts": {
41 | "test": "echo \"Error: run tests from root\" && exit 1"
42 | },
43 | "peerDependencies": {
44 | "react": ">=17.x",
45 | "react-dom": ">=17.x",
46 | "uiw": ">=4.x"
47 | },
48 | "dependencies": {
49 | "@babel/runtime": "~7.20.0",
50 | "@kkt/pro": "1.0.10"
51 | },
52 | "devDependencies": {
53 | "@types/react": "~18.0.25",
54 | "@types/react-dom": "~18.0.11",
55 | "react": "18.2.0",
56 | "react-dom": "18.2.0",
57 | "react-router": "^6.8.0",
58 | "react-router-dom": "^6.8.0",
59 | "uiw": "^4.21.26"
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/packages/layout-tabs/src/styles/index.css:
--------------------------------------------------------------------------------
1 | .uiw-layout-tabs-warp {
2 | margin: -14px;
3 | position: relative;
4 | }
5 | .uiw-tabs-warp {
6 | position: sticky;
7 | top: -14px;
8 | z-index: 9;
9 | background: #fff;
10 | border-bottom: 1px solid ;
11 | padding: 3px;
12 | border-bottom: 1px solid #e9e9e9;
13 | }
14 | .uiw-tabs-warp .w-tabs-flow-content {
15 | display: inline-flex;
16 | align-items: center;
17 | position: relative;
18 | z-index: 9;
19 |
20 | }
21 | .uiw-tabs-warp .w-tabs-bar::-webkit-scrollbar {
22 | height: 0px;
23 | }
24 | .uiw-tabs-warp .w-tabs-item {
25 | border-radius: 4px !important;
26 | border-bottom: 1px solid #d9d9d9 !important;
27 | bottom: 0 !important;
28 | height: 32px;
29 | display: inline-flex;
30 | align-items: center;
31 | }
32 | .uiw-tabs-warp .w-tabs-item .w-icon {
33 | position: relative;
34 | right: -7px;
35 | width: 22px;
36 | height: 22px;
37 | display: flex;
38 | align-items: center;
39 | justify-content: center;
40 | border-radius: 50%;
41 | font-size: 12px;
42 | margin-left: 3px !important;
43 | transition: background .5s;
44 | }
45 | .uiw-tabs-warp .w-tabs-item:hover .w-icon {
46 | background: rgba(167, 182, 194, 0.3);
47 | }
48 | .uiw-tabs-warp .w-tabs-flow-content > span {
49 | line-height: 1;
50 | position: relative;
51 | top: -5px;
52 | }
53 | .uiw-tabs-warp .w-tabs-bar {
54 | height: 100%;
55 | }
56 | .uiw-tabs-warp .w-tabs-nav::after {
57 | display: none !important;
58 | }
59 | .uiw-layout-tabs-warp .uiw-layout-tabs-body {
60 | margin: 14px;
61 | height: calc(100% - 64px);
62 | box-sizing: border-box;
63 | }
--------------------------------------------------------------------------------
/packages/layout-tabs/src/utils.ts:
--------------------------------------------------------------------------------
1 | import { KktproRoutesProps } from '@kkt/pro';
2 | import { Location } from 'react-router-dom';
3 | import { matchPath } from 'react-router';
4 |
5 | /** 把数组扁平化 用于 选项卡渲染 */
6 | export const getRoutesList = (data: any[] = []) => {
7 | const list: any[] = [];
8 | (function returnArr(arr) {
9 | arr.forEach((item) => {
10 | if (item.children) {
11 | returnArr(item.children);
12 | } else {
13 | list.push(item);
14 | }
15 | });
16 | })(data);
17 | return list;
18 | };
19 |
20 | const getO = (routeListData: KktproRoutesProps[], location: Location) => {
21 | return routeListData.find((item) => {
22 | if (location.pathname === '/' && item.index && item.redirect) {
23 | return item.index;
24 | }
25 | if (
26 | location &&
27 | location.pathname &&
28 | item.path &&
29 | location.pathname !== '/'
30 | ) {
31 | return location.pathname === item.path;
32 | }
33 | return false;
34 | });
35 | };
36 |
37 | const getM = (routeListData: KktproRoutesProps[], location: Location) => {
38 | return routeListData.find((item) => {
39 | if (location.pathname === '/' && item.index && item.redirect) {
40 | return item.index;
41 | }
42 | if (
43 | location &&
44 | location.pathname &&
45 | item.path &&
46 | location.pathname !== '/'
47 | ) {
48 | return matchPath({ path: item.path }, location.pathname);
49 | }
50 | return false;
51 | });
52 | };
53 |
54 | export const getMatch = (
55 | routeListData: KktproRoutesProps[],
56 | location: Location,
57 | ) => {
58 | const o = getO(routeListData, location);
59 | if (o) {
60 | return {
61 | current: o,
62 | isMatch: false,
63 | };
64 | } else {
65 | const match = getM(routeListData, location);
66 | return {
67 | current: match,
68 | isMatch: match ? true : false,
69 | };
70 | }
71 | };
72 |
73 | export const getMatchRender = (
74 | routeListData: (KktproRoutesProps & {
75 | location: Location;
76 | isMatch: boolean;
77 | })[],
78 | location: Location,
79 | isMatch: boolean,
80 | ) => {
81 | if (isMatch) {
82 | return getM(routeListData, location) as KktproRoutesProps & {
83 | location: Location;
84 | isMatch: boolean;
85 | };
86 | } else {
87 | return getO(routeListData, location) as KktproRoutesProps & {
88 | location: Location;
89 | isMatch: boolean;
90 | };
91 | }
92 | };
93 |
--------------------------------------------------------------------------------
/packages/layout-tabs/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig",
3 | "include": ["src/**/*"],
4 | "compilerOptions": {
5 | "baseUrl": "./"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/packages/markdown-navbar/README.md:
--------------------------------------------------------------------------------
1 | # markdown-navbar
2 |
3 |
4 | [](https://www.npmjs.com/package/@uiw-admin/markdown-navbar)
--------------------------------------------------------------------------------
/packages/markdown-navbar/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@uiw-admin/markdown-navbar",
3 | "version": "6.1.9",
4 | "description": "markdown导航栏",
5 | "author": "xingyuefeng <15262870437@163.com>",
6 | "homepage": "https://github.com/uiwjs/uiw-admin#readme",
7 | "license": "MIT",
8 | "main": "lib/index.js",
9 | "module": "esm/index.js",
10 | "directories": {
11 | "lib": "lib",
12 | "test": "__tests__"
13 | },
14 | "files": [
15 | "lib",
16 | "esm",
17 | "src"
18 | ],
19 | "repository": {
20 | "type": "git",
21 | "url": "git+https://github.com/uiwjs/uiw-admin.git"
22 | },
23 | "keywords": [
24 | "design",
25 | "uiw",
26 | "uiw-react",
27 | "uiw-admin",
28 | "react.js",
29 | "react",
30 | "markdown-navbar"
31 | ],
32 | "peerDependencies": {
33 | "react": ">=17.x",
34 | "react-dom": ">=17.x"
35 | },
36 | "dependencies": {
37 | "lodash-es": "^4.17.21"
38 | },
39 | "devDependencies": {
40 | "@types/lodash-es": "^4.17.6"
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/packages/markdown-navbar/src/style.css:
--------------------------------------------------------------------------------
1 | .uiw-admin-navbox {
2 | position: fixed;
3 | padding-top: 20px;
4 | border-left: 1px solid #ddd;
5 | }
6 |
7 | .uiw-admin-navbox-active {
8 | color:#008ef0;
9 | border-left: 1px solid #008ef0;
10 | margin-left: -1px;
11 | }
--------------------------------------------------------------------------------
/packages/markdown-navbar/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig",
3 | "include": ["src/**/*"],
4 | "compilerOptions": {
5 | "baseUrl": "./"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/packages/models/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@uiw-admin/models",
3 | "version": "6.1.9",
4 | "description": "models",
5 | "author": "Kenny Wong ",
6 | "homepage": "https://github.com/uiwjs/uiw-admin/tree/master/packages/models#readme",
7 | "license": "MIT",
8 | "main": "lib/index.js",
9 | "module": "esm/index.js",
10 | "files": [
11 | "lib",
12 | "esm"
13 | ],
14 | "publishConfig": {
15 | "access": "public"
16 | },
17 | "keywords": [
18 | "design",
19 | "uiw",
20 | "uiw-react",
21 | "uiw-admin",
22 | "react.js",
23 | "react",
24 | "react-component",
25 | "component",
26 | "components",
27 | "ui",
28 | "css",
29 | "uikit",
30 | "react-ui",
31 | "framework",
32 | "front-end",
33 | "frontend"
34 | ],
35 | "repository": {
36 | "type": "git",
37 | "url": "git+https://github.com/uiwjs/uiw-admin.git"
38 | },
39 | "scripts": {
40 | "test": "echo \"Error: run tests from root\" && exit 1"
41 | },
42 | "dependencies": {
43 | "@rematch/core": "2.2.0",
44 | "@rematch/loading": "2.1.2"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/packages/models/src/index.ts:
--------------------------------------------------------------------------------
1 | import {
2 | RematchRootState,
3 | RematchDispatch,
4 | Model,
5 | RematchStore,
6 | } from '@rematch/core';
7 | import { ExtraModelsFromLoading } from '@rematch/loading';
8 | /** @@ 指向 /src/.uiw 目录 */
9 | import { store, RootModel } from '@@/rematch';
10 | export { store };
11 |
12 | export type FullModel = ExtraModelsFromLoading;
13 | const stores = store as RematchStore;
14 | export const { dispatch, addModel } = stores;
15 | export type Store = RematchStore;
16 | export type AddModel = typeof addModel;
17 | // 对象方式的 Dispatch 类型
18 | export type Dispatch = RematchDispatch;
19 | export type RootState = RematchRootState;
20 | export type ModelDefault = Model;
21 | export * from '@@/rematch';
22 |
--------------------------------------------------------------------------------
/packages/models/src/react-app-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | declare module '@@/rematch' {
3 | const store: any;
4 | interface RootModel {
5 | [s: string]: any;
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/packages/models/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig",
3 | "include": ["src/**/*"],
4 | "compilerOptions": {
5 | "baseUrl": "./"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/packages/plugins/README.md:
--------------------------------------------------------------------------------
1 | # 插件
2 |
3 | [](https://www.npmjs.com/package/@uiw-admin/plugins)
4 |
5 | 当前插件一般为内置插件
6 |
7 | ```bash
8 | npm i @uiw-admin/plugins -D
9 | ```
10 |
11 | ## RematchWebpackPlugin
12 |
13 | > 1. 自动加载 models
14 |
15 | ### lazyLoad
16 |
17 | 1. 类型:`boolean` ,默认 `false`,
18 |
19 | ```ts
20 | //kktrc.ts
21 | import defaultConfig from "@uiw-admin/config"
22 | import { RematchWebpackPlugin } from "@uiw-admin/plugins"
23 | export default defaultConfig({
24 | plugins: [RematchWebpackPlugin()],
25 | // 或者 plugins: [@uiw-admin/plugins/lib/rematch],
26 | ```
27 |
28 | ### 约定式的 model 组织方式
29 |
30 | 符合以下规则的文件会被认为是 model 文件,
31 |
32 | 1. src/models 下的文件
33 | 2. src/pages 下,子目录中 models 目录下的文件
34 | 3. src/pages 下,子目录中 models.ts 文件
35 |
36 | ```txt
37 |
38 | src
39 | models/a.ts
40 | pages
41 | foo/models/b.ts
42 | test/models.ts
43 |
44 | ```
45 |
46 | ## RoutesWebpackPlugin
47 |
48 | > 1. 路由转化,获取项目根目录下`congfig`文件夹下的`routes.json`或`routes.ts`或`routes.js`文件
49 | > 2. 优先级 json > ts > js
50 |
51 | ```ts
52 | //kktrc.ts
53 | import defaultConfig from "@uiw-admin/config"
54 | import { RoutesWebpackPlugin } from "@uiw-admin/plugins"
55 | export default defaultConfig({
56 | plugins: [RoutesWebpackPlugin()],
57 | // 或者 plugins: [@uiw-admin/plugins/lib/routes],
58 | ```
59 |
60 | ## 贡献者
61 |
62 | 感谢所有的贡献者,欢迎开发者为开源项目贡献力量。
63 |
64 |
65 |
66 |
67 |
68 | ## License
69 |
70 | Licensed under the MIT License.
--------------------------------------------------------------------------------
/packages/plugins/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@uiw-admin/plugins",
3 | "version": "6.1.9",
4 | "description": "plugins",
5 | "author": "Kenny Wong ",
6 | "homepage": "https://github.com/uiwjs/uiw-admin/tree/master/packages/models#readme",
7 | "license": "MIT",
8 | "main": "lib/index.js",
9 | "module": "esm/index.js",
10 | "files": [
11 | "lib",
12 | "esm",
13 | "src"
14 | ],
15 | "publishConfig": {
16 | "access": "public"
17 | },
18 | "keywords": [
19 | "design",
20 | "uiw",
21 | "uiw-react",
22 | "uiw-admin",
23 | "react.js",
24 | "react",
25 | "react-component",
26 | "component",
27 | "components",
28 | "ui",
29 | "css",
30 | "uikit",
31 | "react-ui",
32 | "framework",
33 | "front-end",
34 | "frontend"
35 | ],
36 | "repository": {
37 | "type": "git",
38 | "url": "git+https://github.com/uiwjs/uiw-admin.git"
39 | },
40 | "scripts": {
41 | "test": "echo \"Error: run tests from root\" && exit 1"
42 | },
43 | "devDependencies": {
44 | "@babel/generator": "7.21.3",
45 | "@babel/parser": "7.21.3",
46 | "@babel/template": "7.20.7",
47 | "@babel/traverse": "7.21.3",
48 | "@babel/types": "7.21.3",
49 | "chokidar": "3.5.3",
50 | "swr": "^1.3.0"
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/packages/plugins/src/index.ts:
--------------------------------------------------------------------------------
1 | export { default as RematchWebpackPlugin } from './rematch';
2 |
3 | export { default as RoutesWebpackPlugin } from './routes';
4 |
5 | export { default as InitIndexWebpackPlugin } from './initIndex';
6 |
--------------------------------------------------------------------------------
/packages/plugins/src/initIndex/index.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 对项目入口文件进行自动生成
3 | * */
4 | import webpack from 'webpack';
5 | import { PublicConfiguration } from 'swr/dist/types';
6 | import fs from 'fs';
7 | import path from 'path';
8 | import { getInitIndexTemp, getInitCssTemp } from './temp';
9 | import chokidar from 'chokidar';
10 |
11 | export interface InitIndexWebpackPluginProps {
12 | swr?: boolean | undefined | Partial;
13 | routeType?: 'history' | 'hash' | 'browser';
14 | }
15 |
16 | class InitIndexWebpackPlugin {
17 | globalCss: boolean = false;
18 | swr: InitIndexWebpackPluginProps['swr'] = false;
19 | SWRConfig: Partial | undefined = undefined;
20 | routeType: InitIndexWebpackPluginProps['routeType'] = undefined;
21 |
22 | constructor(props?: InitIndexWebpackPluginProps) {
23 | if (Reflect.has(props || {}, 'swr')) {
24 | if (typeof Reflect.get(props || {}, 'swr') === 'boolean') {
25 | this.swr = props?.swr;
26 | } else if (typeof Reflect.get(props || {}, 'swr') === 'object') {
27 | this.swr = true;
28 | this.SWRConfig = props?.swr as Partial;
29 | }
30 | }
31 | if (Reflect.has(props || {}, 'routeType')) {
32 | this.routeType = props?.routeType;
33 | }
34 | }
35 |
36 | init() {
37 | if (fs.existsSync(path.resolve(process.cwd(), 'src/global.css'))) {
38 | this.globalCss = true;
39 | } else {
40 | this.globalCss = false;
41 | }
42 | const initIndexs = getInitIndexTemp({
43 | swr: this.swr as boolean,
44 | SWRConfig: this.SWRConfig,
45 | routeType: this.routeType,
46 | globalCss: this.globalCss,
47 | });
48 | if (!fs.existsSync(path.resolve(process.cwd(), 'src/.uiw'))) {
49 | fs.mkdirSync(path.resolve(process.cwd(), 'src/.uiw'));
50 | }
51 | fs.writeFileSync(
52 | path.resolve(process.cwd(), 'src/.uiw/index.tsx'),
53 | initIndexs,
54 | { encoding: 'utf-8', flag: 'w+' },
55 | );
56 | fs.writeFileSync(
57 | path.resolve(process.cwd(), 'src/.uiw/index.css'),
58 | getInitCssTemp(),
59 | { encoding: 'utf-8', flag: 'w+' },
60 | );
61 | }
62 |
63 | apply(compiler: webpack.Compiler) {
64 | compiler.hooks.initialize.tap('InitIndexWebpackPlugin', () => {
65 | this.init();
66 | this.listenGlobalCss();
67 | });
68 | }
69 |
70 | // 监听 global.css 文件是否删除或添加
71 | listenGlobalCss() {
72 | if (process.env.NODE_ENV === 'development') {
73 | chokidar
74 | .watch(path.resolve(process.cwd(), 'src/global.css'), {
75 | cwd: path.resolve(process.cwd(), 'src'),
76 | })
77 | .on('all', (event, path) => {
78 | if (['add', 'unlink'].includes(event) && /global.css/.test(path)) {
79 | this.init();
80 | }
81 | });
82 | }
83 | }
84 | }
85 |
86 | export default InitIndexWebpackPlugin;
87 |
--------------------------------------------------------------------------------
/packages/plugins/src/initIndex/temp.ts:
--------------------------------------------------------------------------------
1 | export interface ConfigInitIndexProps {
2 | swr?: boolean;
3 | globalCss?: boolean;
4 | SWRConfig?: any;
5 | routeType?: 'history' | 'hash' | 'browser';
6 | }
7 |
8 | export const getInitIndexTemp = (config: ConfigInitIndexProps) => {
9 | return `
10 | // @ts-ignore
11 | import React from 'react'
12 | import ReactDOM from 'react-dom'
13 | import Control from '@uiw-admin/router-control'
14 | import '@uiw/reset.css'
15 | import './index.css'
16 | ${(config.swr && "import { request } from '@uiw-admin/utils'") || ''}
17 | ${(config.swr && "import { SWRConfig } from 'swr'") || ''}
18 | ${(config.globalCss && "import '@/global.css'") || ''}
19 | ReactDOM.render(
20 | ${
21 | config.swr
22 | ? ` {
26 | return request(resource, init)
27 | },
28 | provider: () => new Map()
29 | }}
30 | >
31 |
34 | `
35 | : ` `
38 | },
39 | document.getElementById('root')
40 | )
41 | `;
42 | };
43 |
44 | export const getInitCssTemp = () => {
45 | return `
46 | #root, body, html {
47 | height: 100%;
48 | }
49 |
50 | `;
51 | };
52 |
--------------------------------------------------------------------------------
/packages/plugins/src/rematch/utils.ts:
--------------------------------------------------------------------------------
1 | import fs from 'fs';
2 | import { IsModel } from './../utils';
3 | /**获取model文件信息*/
4 | export const getModelInfo = (newPath: string) => {
5 | // 1. 判断是否已经存在
6 | // 如果已经存在着直接更新
7 | /**是否是model*/
8 | let isMode = false;
9 | /**model 名称*/
10 | let modelName: undefined;
11 | /** model 是否使用 createModel 导出 */
12 | let isCreateModel = false;
13 | // 先判断路径是否存在models 和ts|js 结尾
14 | if (/\.(ts|js)$/.test(newPath) && /models/.test(newPath)) {
15 | const {
16 | isModels,
17 | modelNames,
18 | isCreateModel: isCreate,
19 | } = IsModel(fs.readFileSync(newPath, { encoding: 'utf-8' }));
20 | modelName = modelNames;
21 | isMode = isModels;
22 | isCreateModel = isCreate;
23 | }
24 | return {
25 | /**是否是model*/
26 | modelName,
27 | /**model 名称*/
28 | isMode,
29 | /** model 是否使用 createModel 导出 */
30 | isCreateModel,
31 | };
32 | };
33 |
--------------------------------------------------------------------------------
/packages/plugins/src/routes/temp.ts:
--------------------------------------------------------------------------------
1 | // 模板
2 | export default (
3 | routeStr: string,
4 | iconsList: string[],
5 | isType: 'ts' | 'js' | 'json' | boolean,
6 | ) => {
7 | let reactTemp = `import React from "react"`;
8 | const iconStr = createIcons(iconsList);
9 | if (['js', 'ts'].includes(isType as string)) {
10 | // 1. 判断是否 已经存在 from "react"
11 | const isReact = !/\/\/(.+|)import React.+ from "react"/.test(routeStr);
12 | return `
13 | // @ts-nocheck
14 | ${(!isReact && reactTemp) || ''}
15 | import {Exceptions404,Exceptions403,Exceptions500 } from "@uiw-admin/exceptions"
16 | ${iconStr}
17 | ${routeStr};
18 | `;
19 | }
20 | return `
21 | // @ts-nocheck
22 | import React from "react";
23 | ${iconStr}
24 | import {Exceptions404,Exceptions403,Exceptions500 } from "@uiw-admin/exceptions"
25 | export default ${routeStr};
26 | `;
27 | };
28 |
29 | // 创建 icon 图标
30 | export const createIcons = (iconsList: string[]) => {
31 | let iconStr = '';
32 | iconsList.forEach((key) => {
33 | const [icon] = key.split('_');
34 | iconStr += `import { ${icon} as ${key} } from "@uiw/icons/lib/${icon}";\n`;
35 | });
36 | return iconStr;
37 | };
38 |
--------------------------------------------------------------------------------
/packages/plugins/src/utils/interface.ts:
--------------------------------------------------------------------------------
1 | export interface RoutersProps {
2 | /** 默认跳转 */
3 | index?: boolean;
4 | /** 路径 */
5 | path?: string;
6 | /** 名称 */
7 | name?: string;
8 | /** 图标 */
9 | icon?: string | React.ReactNode;
10 | /** 重定向 当 index===true生效 */
11 | redirect?: string;
12 | /** 组件 */
13 | component?: string;
14 | /** 子集 路由 */
15 | routes?: RoutersProps[];
16 | /** 是否隐藏菜单 */
17 | hideInMenu?: boolean;
18 | /** 用于路由校验权限 */
19 | isAuth?: boolean;
20 | }
21 |
22 | export type ModelType = {
23 | /** 路径 */
24 | path: string;
25 | /** 文件名称 */
26 | filename: string;
27 | /** model 名称 */
28 | modelName?: string;
29 | /** 是否是 createModel 进行包裹 */
30 | isCreateModel: boolean;
31 | /** 所在路径位置 */
32 | location: string;
33 | /** model 名称 */
34 | name: string;
35 | srcPath: string;
36 | };
37 |
38 | /**
39 | * @description 生成的映射json文件格式
40 | * {
41 | * "path":[
42 | * {name:"",path:"....path"}
43 | * ]
44 | * }
45 | * */
46 |
47 | export type RouteModels = Record<
48 | string,
49 | {
50 | name: string;
51 | path: string;
52 | }[]
53 | >;
54 |
--------------------------------------------------------------------------------
/packages/plugins/src/utils/rematch.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 获取目录下所有的model文件
3 | * */
4 | import fs from 'fs';
5 | import path from 'path';
6 | import { ModelType } from './interface';
7 | import { IsModel } from '.';
8 | export const getFilenameInfo = (filedir: string, root: string) => {
9 | const fileName = path.basename(filedir).replace(/\.(ts|js)$/, '');
10 | const pathUrls = `${filedir}`.replace(/\\/g, '/');
11 | const location = pathUrls.replace(/\/models.*$/, '');
12 | const srcPath = pathUrls.replace(new RegExp(root), '.');
13 | return {
14 | fileName,
15 | location,
16 | srcPath,
17 | pathUrls,
18 | };
19 | };
20 |
21 | export class RematchFiles {
22 | modelList: ModelType[] = [];
23 | root: string = '';
24 | constructor(root: string) {
25 | this.root = root;
26 | this.loopInit(root);
27 | }
28 | // 递归文件
29 | loopInit(filePath: string, isModel = false) {
30 | const files = fs.readdirSync(filePath);
31 | if (files) {
32 | files.forEach((filename: string) => {
33 | let mode = isModel;
34 | const filedir = path.join(filePath, filename);
35 | const isNoEmty = fs.existsSync(filedir);
36 | if (!isNoEmty) {
37 | return;
38 | }
39 | const stats = fs.statSync(filedir);
40 | if (stats) {
41 | const isFile = stats.isFile(); //是文件
42 | const isDir = stats.isDirectory(); //是文件夹
43 | if (isFile && isModel && /\.(ts||js)$/.test(filename)) {
44 | const data = fs.readFileSync(filedir, { encoding: 'utf-8' });
45 | const { isModels, modelNames, isCreateModel } = IsModel(data);
46 | const { pathUrls, location, srcPath, fileName } = getFilenameInfo(
47 | filedir,
48 | this.root,
49 | );
50 | // const pathUrls = `${filedir}`.replace(/\\/g, '/');
51 | // const location = pathUrls.replace(/\/models.*$/, '');
52 | // const srcPath = pathUrls.replace(new RegExp(this.root), '.');
53 | if (isModels) {
54 | this.modelList.push({
55 | path: pathUrls,
56 | filename: fileName,
57 | modelName: modelNames,
58 | isCreateModel,
59 | location,
60 | name: modelNames || fileName,
61 | srcPath,
62 | });
63 | }
64 | }
65 | if (filename === 'models') {
66 | mode = true;
67 | }
68 | if (isDir) {
69 | this.loopInit(filedir, mode); //递归,如果是文件夹,就继续遍历该文件夹下面的文件
70 | }
71 | }
72 | });
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/packages/plugins/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig",
3 | "include": ["src/**/*"],
4 | "compilerOptions": {
5 | "baseUrl": "./"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/packages/router-control/README.md:
--------------------------------------------------------------------------------
1 | # 路由
2 |
3 | [](https://www.npmjs.com/package/@uiw-admin/router-control)
4 |
5 | 导出路由相关方法
6 |
7 |
8 |
9 | ## 安装
10 |
11 | ```bash
12 | npm i @uiw-admin/router-control --save # yarn add @uiw-admin/router-control
13 | ```
14 |
15 | ## 参数
16 |
17 | 当前配置参数配合[@uiw-admin/basic-layouts](https://github.com/uiwjs/uiw-admin/tree/yb/packages/basic-layouts)使用
18 |
19 | ``` ts
20 | export interface RoutesBaseProps {
21 | key?: string;
22 | /** 默认跳转 */
23 | index?: boolean;
24 | /** 路径 */
25 | path?: string;
26 | /** 名称 */
27 | name?: string;
28 | /** 图标 */
29 | icon?: string | React.ReactNode;
30 | /** 重定向 当 index===true生效 */
31 | redirect?: string;
32 | /** 子集 路由 */
33 | children?: RoutesBaseProps[];
34 | /** 隐藏主菜单 */
35 | hiddenMainMenu?: boolean;
36 | /** 是否隐藏菜单 */
37 | hideInMenu?: boolean;
38 | /** 用于路由校验权限 */
39 | isAuth?: boolean;
40 | /** 自定义 跳转 */
41 | // navigate?: (navigate: NavigateFunction) => void;
42 | navigate?: string;
43 | /** 控制是否侧边只展示子路由 **/
44 | side?: boolean;
45 | }
46 | ```
47 |
48 | ## 贡献者
49 |
50 | 感谢所有的贡献者,欢迎开发者为开源项目贡献力量。
51 |
52 |
53 |
54 |
55 |
56 | ## License
57 |
58 | Licensed under the MIT License.
--------------------------------------------------------------------------------
/packages/router-control/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@uiw-admin/router-control",
3 | "version": "6.1.9",
4 | "description": "router-control",
5 | "author": "Kenny Wong ",
6 | "homepage": "https://github.com/uiwjs/uiw-admin/tree/master/packages/router-control#readme",
7 | "repository": {
8 | "type": "git",
9 | "url": "https://github.com/uiwjs/uiw-admin.git"
10 | },
11 | "license": "MIT",
12 | "main": "lib/index.js",
13 | "module": "esm/index.js",
14 | "types": "lib/index.d.ts",
15 | "files": [
16 | "lib",
17 | "esm",
18 | "src"
19 | ],
20 | "publishConfig": {
21 | "access": "public"
22 | },
23 | "keywords": [
24 | "design",
25 | "uiw",
26 | "uiw-react",
27 | "uiw-admin",
28 | "react.js",
29 | "react",
30 | "react-component",
31 | "component",
32 | "components",
33 | "ui",
34 | "css",
35 | "uikit",
36 | "react-ui",
37 | "framework",
38 | "front-end",
39 | "frontend"
40 | ],
41 | "peerDependencies": {
42 | "@babel/runtime": ">=7.10.0",
43 | "react": ">=17.x",
44 | "react-dom": ">=17.x"
45 | },
46 | "dependencies": {
47 | "history": "^5.3.0"
48 | },
49 | "devDependencies": {
50 | "@babel/runtime": "~7.21.0",
51 | "@types/react": "~18.0.25",
52 | "@types/react-dom": "~18.0.11",
53 | "@uiw-admin/exceptions": "6.1.9",
54 | "@uiw-admin/models": "6.1.9",
55 | "@uiw-admin/utils": "6.1.9",
56 | "react": "18.2.0",
57 | "react-dom": "18.2.0",
58 | "react-redux": "^7.2.6",
59 | "react-router": "^6.8.0",
60 | "react-router-dom": "^6.8.0"
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/packages/router-control/src/index.ts:
--------------------------------------------------------------------------------
1 | import { unstable_HistoryRouter, NavigateFunction } from 'react-router-dom';
2 | import type { RouteObject } from 'react-router-dom';
3 |
4 | import { createBrowserHistory } from 'history';
5 |
6 | export * from 'react-router-dom';
7 | export * from 'react-router';
8 | export * from 'react-redux';
9 |
10 | export const HistoryRouter = unstable_HistoryRouter;
11 | export const history = createBrowserHistory();
12 | export let navigate: NavigateFunction = () => {};
13 |
14 | export interface RoutesBaseProps extends Omit {
15 | key?: string;
16 | /** 默认跳转 */
17 | index?: boolean;
18 | /** 路径 */
19 | path?: string;
20 | /** 名称 */
21 | name?: string;
22 | /** 图标 */
23 | icon?: string | React.ReactNode;
24 | /** 重定向 当 index===true生效 */
25 | redirect?: string;
26 | /** 子集 路由 */
27 | children?: RoutesBaseProps[];
28 | /** 隐藏主菜单 */
29 | hiddenMainMenu?: boolean;
30 | /** 是否隐藏菜单 */
31 | hideInMenu?: boolean;
32 | /** 用于路由校验权限 */
33 | isAuth?: boolean;
34 | /** 自定义 跳转 */
35 | // navigate?: (navigate: NavigateFunction) => void;
36 | navigate?: string;
37 | /** 控制是否侧边只展示子路由 **/
38 | side?: boolean;
39 | [k: string]: any;
40 | }
41 |
--------------------------------------------------------------------------------
/packages/router-control/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig",
3 | "include": ["src/**/*"],
4 | "compilerOptions": {
5 | "baseUrl": "./"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/packages/uiw-admin/LICENSE:
--------------------------------------------------------------------------------
1 | MIT LICENSE
2 |
3 | Copyright (c) 2020-present uiw
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining
6 | a copy of this software and associated documentation files (the
7 | "Software"), to deal in the Software without restriction, including
8 | without limitation the rights to use, copy, modify, merge, publish,
9 | distribute, sublicense, and/or sell copies of the Software, and to
10 | permit persons to whom the Software is furnished to do so, subject to
11 | the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be
14 | included in all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/packages/uiw-admin/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "uiw-admin",
3 | "version": "6.1.9",
4 | "description": "UIW Admin Project",
5 | "repository": {
6 | "type": "git",
7 | "url": "https://github.com/uiwjs/uiw-admin.git"
8 | },
9 | "keywords": [
10 | "uiw",
11 | "react",
12 | "admin",
13 | "uiw-admin"
14 | ],
15 | "publishConfig": {
16 | "access": "public"
17 | },
18 | "author": "jaywcjlove",
19 | "license": "MIT"
20 | }
21 |
--------------------------------------------------------------------------------
/packages/uiw-admin/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig",
3 | "include": ["src/**/*"],
4 | "compilerOptions": {
5 | "baseUrl": "./"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/packages/user-login/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@uiw-admin/user-login",
3 | "version": "6.1.9",
4 | "description": "Divider component",
5 | "author": "Kenny Wong ",
6 | "homepage": "https://github.com/uiwjs/uiw-admin/tree/master/packages/user-login#readme",
7 | "repository": {
8 | "type": "git",
9 | "url": "https://github.com/uiwjs/uiw-admin.git"
10 | },
11 | "license": "MIT",
12 | "main": "lib/index.js",
13 | "module": "esm/index.js",
14 | "files": [
15 | "lib",
16 | "esm",
17 | "src"
18 | ],
19 | "publishConfig": {
20 | "access": "public"
21 | },
22 | "keywords": [
23 | "design",
24 | "uiw",
25 | "uiw-react",
26 | "uiw-admin",
27 | "react.js",
28 | "react",
29 | "react-component",
30 | "component",
31 | "components",
32 | "ui",
33 | "css",
34 | "uikit",
35 | "react-ui",
36 | "framework",
37 | "front-end",
38 | "frontend"
39 | ],
40 | "peerDependencies": {
41 | "@babel/runtime": ">=7.10.0",
42 | "react": ">=17.x",
43 | "react-dom": ">=17.x",
44 | "uiw": ">=4.x"
45 | },
46 | "dependencies": {
47 | "@kkt/request": "^1.0.13",
48 | "@uiw-admin/document-title": "6.1.9",
49 | "classnames": "^2.3.1"
50 | },
51 | "devDependencies": {
52 | "@babel/runtime": "~7.21.0",
53 | "@types/classnames": "2.3.1",
54 | "@types/react": "~18.0.25",
55 | "@types/react-dom": "~18.0.11",
56 | "@uiw-admin/utils": "6.1.9",
57 | "react": "18.2.0",
58 | "react-dom": "18.2.0",
59 | "uiw": "^4.21.26"
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/packages/user-login/src/assets/bg.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uiwjs/uiw-admin/f4abb975dd6a203b5755df1b5e025596204d9186/packages/user-login/src/assets/bg.jpeg
--------------------------------------------------------------------------------
/packages/user-login/src/assets/r2g7rm.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uiwjs/uiw-admin/f4abb975dd6a203b5755df1b5e025596204d9186/packages/user-login/src/assets/r2g7rm.jpg
--------------------------------------------------------------------------------
/packages/user-login/src/react-app-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | declare module '*.jpg' {
4 | const src: string;
5 | export default src;
6 | }
7 |
--------------------------------------------------------------------------------
/packages/user-login/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig",
3 | "include": ["src/**/*"],
4 | "compilerOptions": {
5 | "baseUrl": "./"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/packages/utils/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@uiw-admin/utils",
3 | "version": "6.1.9",
4 | "description": "> TODO: description",
5 | "author": "xingyuefeng <15262870437@163.com>",
6 | "homepage": "https://github.com/uiwjs/uiw-admin#readme",
7 | "license": "MIT",
8 | "main": "lib/index.js",
9 | "module": "esm/index.js",
10 | "directories": {
11 | "lib": "lib"
12 | },
13 | "files": [
14 | "esm",
15 | "src",
16 | "lib"
17 | ],
18 | "repository": {
19 | "type": "git",
20 | "url": "git+https://github.com/uiwjs/uiw-admin.git"
21 | },
22 | "scripts": {
23 | "test": "echo \"Error: run tests from root\" && exit 1"
24 | },
25 | "bugs": {
26 | "url": "https://github.com/uiwjs/uiw-admin/issues"
27 | },
28 | "dependencies": {
29 | "axios": "^0.27.0",
30 | "qs": "~6.10.3"
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/packages/utils/src/cookies.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Description: cookie 操作
3 | */
4 |
5 | /** 设置 cookies */
6 | export function setCookie(name: string, value: string, days: number = 30) {
7 | const exp = new Date();
8 | exp.setTime(exp.getTime() + days * 24 * 60 * 60 * 1000);
9 | document.cookie =
10 | name + '=' + escape(value) + ';expires=' + exp.toUTCString();
11 | }
12 |
13 | /** 读取 cookies */
14 | export function getCookie(name: string) {
15 | let arr,
16 | reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)');
17 | if ((arr = document.cookie.match(reg))) return unescape(arr[2]);
18 | else return null;
19 | }
20 |
21 | /** 删除 cookies */
22 | export function delCookie(name: string) {
23 | const exp = new Date();
24 | exp.setTime(exp.getTime() - 1);
25 | const cval = getCookie(name);
26 | if (cval != null)
27 | document.cookie = name + '=' + cval + ';expires=' + exp.toUTCString();
28 | }
29 |
--------------------------------------------------------------------------------
/packages/utils/src/index.ts:
--------------------------------------------------------------------------------
1 | import request from './request';
2 | import { splitUrl } from './utils';
3 |
4 | export { request, splitUrl };
5 |
6 | export * from './cookies';
7 |
--------------------------------------------------------------------------------
/packages/utils/src/utils.ts:
--------------------------------------------------------------------------------
1 | // 拼接url参数
2 | export function splitUrl(url: string, options: { [x: string]: any }) {
3 | let urlNew = url;
4 | const paramsArray: string[] = [];
5 | // Object.keys(options).forEach(key => paramsArray.push(key + '=' + options[key]));
6 | Object.keys(options).forEach((key) =>
7 | paramsArray.push(`${key}=${options[key]}`),
8 | );
9 | if (Object.keys(options).length === 0) {
10 | return url;
11 | }
12 | if (/\?/.test(urlNew) === false) {
13 | urlNew = `${urlNew}?${paramsArray.join('&')}`;
14 | } else {
15 | urlNew += `&${paramsArray.join('&')}`;
16 | }
17 | return urlNew;
18 | }
19 |
--------------------------------------------------------------------------------
/packages/utils/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig",
3 | "include": ["src/**/*"],
4 | "compilerOptions": {
5 | "baseUrl": "./"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/renovate.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["config:base"],
3 | "packageRules": [
4 | {
5 | "matchPackagePatterns": ["*"],
6 | "rangeStrategy": "replace"
7 | }
8 | ]
9 | }
10 |
--------------------------------------------------------------------------------
/script/copy.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 转换 examples/base下除src目录下所有ts文件为js文件
3 | * */
4 | const path = require('path');
5 | const fs = require('fs');
6 | const FS = require('fs-extra');
7 | const ts = require('typescript');
8 | const { transformFileAsync } = require('@babel/core');
9 | const recursiveReaddirFiles = require('recursive-readdir-files');
10 |
11 | const PWDEntry = path.resolve(__dirname, '../examples/base/');
12 | const PWDOutPut = path.resolve(__dirname, '../examples/basejs/');
13 |
14 | // 获取文件
15 | const getFields = async () => {
16 | const dirToFiles = await recursiveReaddirFiles.default(PWDEntry, {
17 | exclude:
18 | /(node_modules|.uiw|build|dist|\.d\.ts|\.(test|spec)\.(ts|tsx|js|jsx))$/,
19 | });
20 | return dirToFiles;
21 | };
22 | // 转换ts tsx代码
23 | const transform = async (paths) => {
24 | const result = await transformFileAsync(paths, {
25 | presets: ['@babel/preset-typescript'],
26 | });
27 | if (result) {
28 | const output = result.options.filename
29 | .replace(PWDEntry, PWDOutPut)
30 | .replace(/\.(ts|tsx)$/, '.js');
31 | ts.sys.writeFile(output, result.code);
32 | }
33 | };
34 | // 循环文件
35 | const fieldMap = async () => {
36 | const fieldArr = (await getFields()) || [];
37 | fieldArr.forEach((item) => {
38 | if (item.ext && /ts|tsx/.test(item.ext)) {
39 | transform(item.path);
40 | } else {
41 | FS.copySync(item.path, item.path.replace(PWDEntry, PWDOutPut));
42 | }
43 | });
44 | };
45 | // 为了后面那一步 修改package.json
46 | const ci = async () => {
47 | await fieldMap();
48 | // 更改 package.json name 名称
49 | const pagPath = path.resolve(__dirname, '../examples/basejs/package.json');
50 | const pagContent = fs.readFileSync(pagPath, { encoding: 'utf-8' });
51 | const newPageContent = pagContent.replace(
52 | /"name": "@examples\/base"/,
53 | `"name": "@examples/basejs"`,
54 | );
55 | fs.writeFileSync(pagPath, newPageContent);
56 | };
57 | ci();
58 |
--------------------------------------------------------------------------------
/test/copy.test.ts:
--------------------------------------------------------------------------------
1 | import fs from 'fs';
2 | import path from 'path';
3 |
4 | it('js案例项目生成测试', async () => {
5 | const srcDir = path.resolve(process.cwd(), 'examples', 'basejs', 'src');
6 | expect(fs.existsSync(srcDir)).toBeTruthy();
7 | const fileNames = fs.readdirSync(`${srcDir}/layouts`);
8 | expect(fileNames).toContain('BasicLayout.js');
9 | });
10 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "sourceMap": false,
4 | "target": "esnext",
5 | "module": "esnext",
6 | "moduleResolution": "node",
7 | "allowJs": false,
8 | "declaration": true,
9 | "strict": true,
10 | "skipLibCheck": true,
11 | "noUnusedLocals": true,
12 | "experimentalDecorators": true,
13 | "resolveJsonModule": true,
14 | "esModuleInterop": true,
15 | "removeComments": false,
16 | "jsx": "react-jsx",
17 | "lib": ["esnext", "dom", "DOM.Iterable"],
18 | "types": ["jest", "node"]
19 | }
20 | }
21 |
--------------------------------------------------------------------------------