Compare commits

..

53 Commits

Author SHA1 Message Date
Vben
553467df56 chore: release v2.0.2 [deploy] 2021-03-04 01:29:04 +08:00
Vben
4628d94415 feat: added system management sample page 2021-03-04 01:25:50 +08:00
Vben
cd8e924d46 perf(tree): strengthen BasicTree function 2021-03-03 23:35:30 +08:00
Vben
9a1ba74920 wip: system management sample page 2021-03-03 22:52:25 +08:00
Vben
f79cae63d9 chore: update deps 2021-03-03 06:19:11 +08:00
Vben
8b62fa0cb0 feat(tree): actionItem added show attribute close #314 2021-03-02 23:57:35 +08:00
Vben
b6bb81630d fix: expose tree information in the event close #315 2021-03-02 23:28:39 +08:00
Vben
72b42d7b35 feat(tree): add renderIcon props close #309 2021-03-02 23:15:32 +08:00
Vben
d67bd496e8 chore: improve icon-picker logic 2021-03-02 21:00:18 +08:00
Vben
e5b2cc1e98 chore: update deps 2021-03-02 06:59:38 +08:00
Vben
7b4fcd2eca fix: fix login page style 2021-03-02 00:40:00 +08:00
Vben
c625462e98 feat(ws): added WebSocket examples and service scripts 2021-03-02 00:28:20 +08:00
Vben
b6cea4a950 feat(icon-picker): add icon-picker component 2021-03-01 23:11:12 +08:00
Vben
b476e1c84c fix: ensure that the correct components are dynamically imported 2021-03-01 23:01:37 +08:00
Vben
3b8ca420c7 feat: add dept management page 2021-03-01 22:54:21 +08:00
Vben
37669d067c wip: add account management page 2021-03-01 00:56:25 +08:00
Vben
c8e84dc14e chore: typo 2021-02-28 23:05:37 +08:00
Vben
15567e478c fix: improve persistent cache logic 2021-02-28 12:25:57 +08:00
Vben
f6cef1088d refactor: refactored multi-language modules to support lazy loading and remote loading 2021-02-28 08:48:53 +08:00
Vben
f57eb944ed perf: improve persistent logic 2021-02-27 19:55:30 +08:00
Vben
11d3f395ca fix: ensure to request the interface correctly 2021-02-26 23:30:22 +08:00
Vben
a821d9a3a2 perf: imporve axios logic 2021-02-26 22:45:53 +08:00
Vben
7c2f851692 fix(table): ensure the table setting button dividing line is hidden 2021-02-26 20:36:54 +08:00
Vben
37508ca411 fix(modal): ensure that the height is correct in the modal full screen state close #308 2021-02-26 20:33:06 +08:00
Vben
ec7bef792b fix: ensure that storage is deleted correctly close #292 2021-02-26 20:21:13 +08:00
Vben
efb27aff0a style(table): remove unless style 2021-02-26 20:15:50 +08:00
Vben
fcee7d4eb7 perf: move src/types to root 2021-02-26 20:09:24 +08:00
Vben
a84586e2f4 fix(login): fix login style close #306 2021-02-26 00:17:50 +08:00
Vben
bba7768759 perf: replace crypto-es with crypto-js 2021-02-26 00:15:18 +08:00
Vben
8a9ca498d7 chore: remove useless code 2021-02-25 20:25:02 +08:00
Vben
5ffac40935 chore: update deps 2021-02-25 05:40:33 +08:00
Vben
601368921f fix(table): get the selected rows of the table correctly 2021-02-24 23:31:39 +08:00
Vben
500900abe1 perf: hide table full screen button by default 2021-02-24 22:05:27 +08:00
Vben
c41fa75265 feat: axios supports form-data format requests 2021-02-24 20:45:53 +08:00
Vben
5cc9488bd6 workflow: add ftp-schedule workflow 2021-02-24 20:45:52 +08:00
VSirrr
5eac9b23d6 fix: change transition-duration to make animate smoothly (#294) 2021-02-24 20:26:02 +08:00
HelKim
66fc1b7845 fix(watermark): watermark causes a blank bar (#297) 2021-02-24 20:25:44 +08:00
Vben
c6f9b0da7e workflow: fix deploy workflow [deploy] 2021-02-24 01:00:42 +08:00
Vben
8ccf778fb7 workflow: update deploy workflow [deploy] 2021-02-24 00:21:29 +08:00
vben
7e564c2984 chore: update deps 2021-02-23 00:31:10 +08:00
vben
a09a0eedd2 perf: improve login logic 2021-02-22 23:04:47 +08:00
vben
be3a3ed699 perf: remove useless code 2021-02-22 00:01:03 +08:00
vben
562189dfb0 chore: bump 2.0.1 2021-02-21 22:41:38 +08:00
vben
9a71029684 chore: update deps 2021-02-21 22:33:47 +08:00
vben
ec9478f76f refactor: refactor login page 2021-02-21 17:56:23 +08:00
vben
e3851dc5ea feat(moda;): can switch full screen by double-clicking on the head close #277 2021-02-20 00:08:22 +08:00
vben
4f8e1c1b5f fix(table): fix known errors in editable tables close #267 2021-02-20 00:00:22 +08:00
vben
e250ad567f fix(style): fix anticon style 2021-02-19 22:15:02 +08:00
vben
422ea3a765 chore: update deps 2021-02-19 22:05:03 +08:00
vben
f675fff2e6 fix(image): fix preview style close #276 2021-02-18 21:12:27 +08:00
vben
da04913ef3 feat: added settingButtonPosition configuration close #275 2021-02-18 21:12:27 +08:00
Leon
7d9b521c69 fix(dashboard): fix workbench page style (#280) 2021-02-18 21:00:28 +08:00
vben
fefcc5eec6 chore: update deps 2021-02-18 06:31:16 +08:00
303 changed files with 8388 additions and 3879 deletions

2
.env
View File

@@ -5,4 +5,4 @@ VITE_PORT = 3100
VITE_GLOB_APP_TITLE = Vben Admin VITE_GLOB_APP_TITLE = Vben Admin
# spa shortname # spa shortname
VITE_GLOB_APP_SHORT_NAME = vue_vben_admin_2x VITE_GLOB_APP_SHORT_NAME = vue_vben_admin

View File

@@ -7,7 +7,7 @@ VITE_PUBLIC_PATH = /
# Delete console # Delete console
VITE_DROP_CONSOLE = true VITE_DROP_CONSOLE = true
# Whether to enable gizp or brotli compression # Whether to enable gzip or brotli compression
# Optional: gzip | brotli | none # Optional: gzip | brotli | none
# If you need multiple forms, you can use `,` to separate # If you need multiple forms, you can use `,` to separate
VITE_BUILD_COMPRESS = 'none' VITE_BUILD_COMPRESS = 'none'

View File

@@ -1,18 +1,25 @@
module.exports = { module.exports = {
root: true,
env: {
browser: true,
node: true,
es6: true,
},
parser: 'vue-eslint-parser', parser: 'vue-eslint-parser',
parserOptions: { parserOptions: {
parser: '@typescript-eslint/parser', parser: '@typescript-eslint/parser',
ecmaVersion: 2020, ecmaVersion: 2020,
sourceType: 'module', sourceType: 'module',
jsxPragma: 'React',
ecmaFeatures: { ecmaFeatures: {
jsx: true, jsx: true,
tsx: true,
}, },
}, },
extends: [ extends: [
'plugin:vue/vue3-recommended', 'plugin:vue/vue3-recommended',
'plugin:@typescript-eslint/recommended', 'plugin:@typescript-eslint/recommended',
'prettier/@typescript-eslint', 'prettier',
'plugin:prettier/recommended', 'plugin:prettier/recommended',
], ],
rules: { rules: {

View File

@@ -6,17 +6,113 @@ on:
- main - main
jobs: jobs:
build-deploy: push-to-ftp:
if: "contains(github.event.head_commit.message, '[deploy]')"
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v1 - name: Checkout
- run: npm install uses: actions/checkout@v2
- run: npm run build
- name: Sed Config Base
shell: bash
run: |
sed -i 's#VITE_PUBLIC_PATH\s*=.*#VITE_PUBLIC_PATH = /next/#g' ./.env.production
sed -i "s#VITE_BUILD_COMPRESS\s*=.*#VITE_BUILD_COMPRESS = 'gzip'#g" ./.env.production
cat ./.env.production
- name: use Node.js 14
uses: actions/setup-node@v2.1.2
with:
node-version: '14.x'
- name: Get yarn cache
id: yarn-cache
run: echo "::set-output name=dir::$(yarn cache dir)"
- name: Cache dependencies
uses: actions/cache@v2
with:
path: ${{ steps.yarn-cache.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Build
run: |
yarn install
yarn run build
- name: Deploy
uses: SamKirkland/FTP-Deploy-Action@2.0.0
env:
FTP_SERVER: ${{ secrets.FTP_SERVER }}
FTP_USERNAME: ${{ secrets.FTP_USERNAME }}
FTP_PASSWORD: ${{ secrets.FTP_PASSWORD }}
METHOD: sftp
PORT: ${{ secrets.FTP_PORT }}
LOCAL_DIR: dist
REMOTE_DIR: /srv/www/vben-admin
ARGS: --delete --verbose --parallel=80
push-to-gh-pages:
if: "contains(github.event.head_commit.message, '[deploy]')"
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Sed Config Base
shell: bash
run: |
sed -i 's#VITE_PUBLIC_PATH\s*=.*#VITE_PUBLIC_PATH = /vue-vben-admin/#g' ./.env.production
sed -i "s#VITE_BUILD_COMPRESS\s*=.*#VITE_BUILD_COMPRESS = 'gzip'#g" ./.env.production
cat ./.env.production
- name: use Node.js 14
uses: actions/setup-node@v2.1.2
with:
node-version: '14.x'
- name: Get yarn cache
id: yarn-cache
run: echo "::set-output name=dir::$(yarn cache dir)"
- name: Cache dependencies
uses: actions/cache@v2
with:
path: ${{ steps.yarn-cache.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Set SSH Environment
env:
DOCS_DEPLOY_KEY: ${{ secrets.ACTIONS_DEPLOY_KEY }}
run: |
mkdir -p ~/.ssh/
echo "$ACTIONS_DEPLOY_KEY" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
ssh-keyscan github.com > ~/.ssh/known_hosts
chmod 700 ~/.ssh && chmod 600 ~/.ssh/*
git config --locale user.email "vbenadmin@163.com"
git config --locale user.name "vbenAdmin"
- name: Delete gh-pages branch
run: |
git push origin --delete gh-pages
- name: Build
run: |
yarn install
yarn run build
touch dist/.nojekyll
cp dist/index.html dist/404.html
- name: Deploy - name: Deploy
uses: peaceiris/actions-gh-pages@v2.5.0 uses: peaceiris/actions-gh-pages@v2.5.0
env: env:
ACTIONS_DEPLOY_KEY: ${{secrets.ACTIONS_DEPLOY_KEY}} ACTIONS_DEPLOY_KEY: ${{secrets.ACTIONS_DEPLOY_KEY}}
PUBLISH_BRANCH: gh-pages PUBLISH_BRANCH: gh-pages
PUBLISH_DIR: dist PUBLISH_DIR: ./dist
with:
forceOrphan: true

55
.github/workflows/ftp-schedule.yml vendored Normal file
View File

@@ -0,0 +1,55 @@
name: schedule-push-to-ftp
# Timed deployment project
on:
push:
schedule:
- cron: '0 15 * * *'
jobs:
schedule-push-to-ftp:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Sed Config Base
shell: bash
run: |
sed -i 's#VITE_PUBLIC_PATH\s*=.*#VITE_PUBLIC_PATH = /next/#g' ./.env.production
sed -i "s#VITE_BUILD_COMPRESS\s*=.*#VITE_BUILD_COMPRESS = 'gzip'#g" ./.env.production
cat ./.env.production
- name: use Node.js 14
uses: actions/setup-node@v2.1.2
with:
node-version: '14.x'
- name: Get yarn cache
id: yarn-cache
run: echo "::set-output name=dir::$(yarn cache dir)"
- name: Cache dependencies
uses: actions/cache@v2
with:
path: ${{ steps.yarn-cache.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Build
run: |
yarn install
yarn run build
- name: Deploy
uses: SamKirkland/FTP-Deploy-Action@2.0.0
env:
FTP_SERVER: ${{ secrets.FTP_SERVER }}
FTP_USERNAME: ${{ secrets.FTP_USERNAME }}
FTP_PASSWORD: ${{ secrets.FTP_PASSWORD }}
METHOD: sftp
PORT: ${{ secrets.FTP_PORT }}
LOCAL_DIR: dist
REMOTE_DIR: /srv/www/vben-admin
ARGS: --delete --verbose --parallel=80

View File

@@ -1,4 +1,4 @@
name: Release name: Create Release
on: on:
push: push:
@@ -6,10 +6,19 @@ on:
- v* - v*
jobs: jobs:
release: build:
name: Create Release
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - name: Checkout code
- run: npx conventional-github-releaser -p angular uses: actions/checkout@master
- name: Create Release for Tag
id: release_tag
uses: yyx990803/release-tag@master
env: env:
CONVENTIONAL_GITHUB_RELEASER_TOKEN: ${{secrets.GITHUB_TOKEN}} GITHUB_TOKEN: ${{ secrets.OPER_TOKEN }}
with:
tag_name: ${{ github.ref }}
body: |
Please refer to [CHANGELOG.md](https://github.com/anncwb/vue-vben-admin/blob/main/CHANGELOG.md) for details.

2
.husky/.gitignore vendored
View File

@@ -1 +1 @@
_ _

View File

@@ -10,3 +10,5 @@ npm run lint:ls-lint
# Format and submit code according to lintstagedrc.js configuration # Format and submit code according to lintstagedrc.js configuration
npm run lint:lint-staged npm run lint:lint-staged
npm run lint:pretty

View File

@@ -17,5 +17,8 @@ ignore:
- .circleci - .circleci
- .github - .github
- .vscode - .vscode
- .idea
- dist - dist
- .local - .local
- .husky
- src/locales/lang

View File

@@ -1,19 +1,13 @@
{ {
"recommendations": [ "recommendations": [
"johnsoncodehk.volar",
"octref.vetur", "octref.vetur",
"dbaeumer.vscode-eslint", "dbaeumer.vscode-eslint",
"stylelint.vscode-stylelint", "stylelint.vscode-stylelint",
"DavidAnson.vscode-markdownlint",
"esbenp.prettier-vscode", "esbenp.prettier-vscode",
"mrmlnc.vscode-less", "mrmlnc.vscode-less",
"antfu.i18n-ally", "lokalise.i18n-ally",
"cpylua.language-postcss",
"Orta.vscode-jest",
"antfu.iconify", "antfu.iconify",
"mikestead.dotenv", "mikestead.dotenv",
"bradlc.vscode-tailwindcss", "heybourn.headwind"
"heybourn.headwind",
"znck.vue-language-features"
] ]
} }

View File

@@ -1,3 +1,58 @@
## 2.0.1 (2021-03-04)
### ✨ Refactor
- Refactored multi-language modules to support lazy loading and remote loading
### ✨ Features
- axios supports form-data format request
- Added icon selector component (support local and online methods)
- Added WebSocket examples and service scripts
- Added the `renderIcon` property to the Tree component to control the display of level icons
- Tree->actionItem added show attribute, used to dynamically control button display
- New toolbar/title/search function for Tree
- Added department management/password modification/account management/role management/menu management sample interface
### ⚡ Performance Improvements
- Optimized login interface animation
- Fix the problem of excessively large github warehouse.
- Hide table full screen button by default
- `crypto-es` is changed to `crypto-js` to reduce the package size
- `types` directory moved to the root directory, compatible with other directory global types
### 🐛 Bug Fixes
- Fix the warning problem of verification code component
- Fix the table cannot get the selected row correctly
- Fixed modal height calculation error in full screen state
- Fix some table style issues
- Fix the invalidation of the tree form `indentSize` setting
## 2.0.1 (2021-02-21)
### ✨ Refactor
- Refactored login page, new registration page/reset password page/mobile phone login/QR code login
### ✨ Features
- Added the `settingButtonPosition` configuration item for configuring the position of the `settings` button
- `modal` can switch the full screen by double-clicking the head
- Added `CountDownInput` component
### ⚡ Performance Improvements
- Optimize the editable center style and the width of the drop-down box is too short
- The `edit-change` event listener when the table is added and edited
### 🐛 Bug Fixes
- Fix image preview style error
- Fix icon style problem
- Fix the drop-down echo problem of editable table
## 2.0.0 (2021-02-18) ## 2.0.0 (2021-02-18)
## Breaking changes ## Breaking changes

454
CHANGELOG.md Normal file
View File

@@ -0,0 +1,454 @@
## [2.0.2](https://github.com/anncwb/vue-vben-admin/compare/v2.0.0...v2.0.2) (2021-03-03)
### Bug Fixes
- change transition-duration to make animate smoothly ([#294](https://github.com/anncwb/vue-vben-admin/issues/294)) ([5eac9b2](https://github.com/anncwb/vue-vben-admin/commit/5eac9b23d6d8ad91e110169519bfd3ab50f985a9))
- ensure that storage is deleted correctly close [#292](https://github.com/anncwb/vue-vben-admin/issues/292) ([ec7bef7](https://github.com/anncwb/vue-vben-admin/commit/ec7bef792b2a780736c2b1713af3638fa0b69eed))
- ensure that the correct components are dynamically imported ([b476e1c](https://github.com/anncwb/vue-vben-admin/commit/b476e1c84c52dab7030fd19b34ecd33e65fadcb2))
- ensure to request the interface correctly ([11d3f39](https://github.com/anncwb/vue-vben-admin/commit/11d3f395caf7e2268630090eb34f4e5c114a96b7))
- expose tree information in the event close [#315](https://github.com/anncwb/vue-vben-admin/issues/315) ([b6bb816](https://github.com/anncwb/vue-vben-admin/commit/b6bb81630de728c146bf0e559bef88b69d4b8a21))
- fix login page style ([7b4fcd2](https://github.com/anncwb/vue-vben-admin/commit/7b4fcd2ecac8107f7d052dee08cb8007dc5e5dd9))
- improve persistent cache logic ([15567e4](https://github.com/anncwb/vue-vben-admin/commit/15567e478c0f274b0f8f0a7410ea5cb636bacc3d))
- **dashboard:** fix workbench page style ([#280](https://github.com/anncwb/vue-vben-admin/issues/280)) ([7d9b521](https://github.com/anncwb/vue-vben-admin/commit/7d9b521c693b59da5fa28130b5753afa0914e598))
- **image:** fix preview style close [#276](https://github.com/anncwb/vue-vben-admin/issues/276) ([f675fff](https://github.com/anncwb/vue-vben-admin/commit/f675fff2e66054b4157b2a330dbf151822b0befd))
- **login:** fix login style close [#306](https://github.com/anncwb/vue-vben-admin/issues/306) ([a84586e](https://github.com/anncwb/vue-vben-admin/commit/a84586e2f49a2966ac5cb02d945e62e107b247d1))
- **modal:** ensure that the height is correct in the modal full screen state close [#308](https://github.com/anncwb/vue-vben-admin/issues/308) ([37508ca](https://github.com/anncwb/vue-vben-admin/commit/37508ca4113701458cae84fff64062427ba43898))
- **style:** fix anticon style ([e250ad5](https://github.com/anncwb/vue-vben-admin/commit/e250ad567f3169d4ef7baec8954be2e18c6932e6))
- **table:** ensure the table setting button dividing line is hidden ([7c2f851](https://github.com/anncwb/vue-vben-admin/commit/7c2f85169248b369f95c5866ef7e90d4fb1739ef))
- **table:** fix known errors in editable tables close [#267](https://github.com/anncwb/vue-vben-admin/issues/267) ([4f8e1c1](https://github.com/anncwb/vue-vben-admin/commit/4f8e1c1b5ffc78242b300e85be22b1fa07c7d902))
- **table:** get the selected rows of the table correctly ([6013689](https://github.com/anncwb/vue-vben-admin/commit/601368921f075aa1870d1c3ce8f4a8330260206a))
- **watermark:** watermark causes a blank bar ([#297](https://github.com/anncwb/vue-vben-admin/issues/297)) ([66fc1b7](https://github.com/anncwb/vue-vben-admin/commit/66fc1b78450fa7846b0d58e6da5f2135e6456238))
### Features
- added system management sample page ([4628d94](https://github.com/anncwb/vue-vben-admin/commit/4628d94415c1787da8b04499e295967f15c4eef5))
- **icon-picker:** add icon-picker component ([b6cea4a](https://github.com/anncwb/vue-vben-admin/commit/b6cea4a950e92a0f91e06bcc60b4653e1d2709ef))
- **moda;:** can switch full screen by double-clicking on the head close [#277](https://github.com/anncwb/vue-vben-admin/issues/277) ([e3851dc](https://github.com/anncwb/vue-vben-admin/commit/e3851dc5ea290ef6eb4d12ce2469311b1bee53cd))
- **tree:** actionItem added show attribute close [#314](https://github.com/anncwb/vue-vben-admin/issues/314) ([8b62fa0](https://github.com/anncwb/vue-vben-admin/commit/8b62fa0cb0559ec3ea8a1b82a2d44165b2337522))
- **tree:** add renderIcon props close [#309](https://github.com/anncwb/vue-vben-admin/issues/309) ([72b42d7](https://github.com/anncwb/vue-vben-admin/commit/72b42d7b3539919a9baa4f1a7316842f85991c1e))
- **ws:** added WebSocket examples and service scripts ([c625462](https://github.com/anncwb/vue-vben-admin/commit/c625462e98eec006aaeeef14280775cafeb72364))
- add dept management page ([3b8ca42](https://github.com/anncwb/vue-vben-admin/commit/3b8ca420c763fe0e386a8dbc023f4f8eb8742252))
- added settingButtonPosition configuration close [#275](https://github.com/anncwb/vue-vben-admin/issues/275) ([da04913](https://github.com/anncwb/vue-vben-admin/commit/da04913ef324fff122732b445c1b1d1d662b87a3))
- axios supports form-data format requests ([c41fa75](https://github.com/anncwb/vue-vben-admin/commit/c41fa75265beb00f629dcda808957cb58b905bc2))
### Performance Improvements
- **tree:** strengthen BasicTree function ([cd8e924](https://github.com/anncwb/vue-vben-admin/commit/cd8e924d4641fc46cacd4a934478d8861e8c3c04))
- hide table full screen button by default ([500900a](https://github.com/anncwb/vue-vben-admin/commit/500900abe16d3e27e1c9e0446a13386c6129d449))
- imporve axios logic ([a821d9a](https://github.com/anncwb/vue-vben-admin/commit/a821d9a3a279f0e6a5b7dbb316725d603ce30f74))
- improve login logic ([a09a0ee](https://github.com/anncwb/vue-vben-admin/commit/a09a0eedd29fdc9a9bd5414bd12c08e37c72982a))
- improve persistent logic ([f57eb94](https://github.com/anncwb/vue-vben-admin/commit/f57eb944edfd967f5f45566ec5bedbf12f147492))
- move src/types to root ([fcee7d4](https://github.com/anncwb/vue-vben-admin/commit/fcee7d4eb71471dd40567c8d7c97302eeee80697))
- remove useless code ([be3a3ed](https://github.com/anncwb/vue-vben-admin/commit/be3a3ed699f73d352d49623ef07288093a3332c4))
- replace crypto-es with crypto-js ([bba7768](https://github.com/anncwb/vue-vben-admin/commit/bba7768759c5d4dedd6599417154c4cb8ab64920))
## [2.0.1](https://github.com/anncwb/vue-vben-admin/compare/v2.0.0...v2.0.1) (2021-02-21)
### Bug Fixes
- **dashboard:** fix workbench page style ([#280](https://github.com/anncwb/vue-vben-admin/issues/280)) ([7d9b521](https://github.com/anncwb/vue-vben-admin/commit/7d9b521c693b59da5fa28130b5753afa0914e598))
- **image:** fix preview style close [#276](https://github.com/anncwb/vue-vben-admin/issues/276) ([f675fff](https://github.com/anncwb/vue-vben-admin/commit/f675fff2e66054b4157b2a330dbf151822b0befd))
- **style:** fix anticon style ([e250ad5](https://github.com/anncwb/vue-vben-admin/commit/e250ad567f3169d4ef7baec8954be2e18c6932e6))
- **table:** fix known errors in editable tables close [#267](https://github.com/anncwb/vue-vben-admin/issues/267) ([4f8e1c1](https://github.com/anncwb/vue-vben-admin/commit/4f8e1c1b5ffc78242b300e85be22b1fa07c7d902))
### Features
- **moda;:** can switch full screen by double-clicking on the head close [#277](https://github.com/anncwb/vue-vben-admin/issues/277) ([e3851dc](https://github.com/anncwb/vue-vben-admin/commit/e3851dc5ea290ef6eb4d12ce2469311b1bee53cd))
- added settingButtonPosition configuration close [#275](https://github.com/anncwb/vue-vben-admin/issues/275) ([da04913](https://github.com/anncwb/vue-vben-admin/commit/da04913ef324fff122732b445c1b1d1d662b87a3))
# [2.0.0](https://github.com/anncwb/vue-vben-admin/compare/v2.0.0-rc.18...v2.0.0) (2021-02-17)
### Bug Fixes
- **i18n:** fix useMessage i18n type [#262](https://github.com/anncwb/vue-vben-admin/issues/262) ([d753155](https://github.com/anncwb/vue-vben-admin/commit/d7531554a274ad9d793ea621739dfffdc7f73db8))
- **table:** fix the table in the editable row status and press Enter to confirm [#258](https://github.com/anncwb/vue-vben-admin/issues/258) ([64533f6](https://github.com/anncwb/vue-vben-admin/commit/64533f6204f96f79c6006d9911e9417cd9800d0d))
- correct debugger code ([759e532](https://github.com/anncwb/vue-vben-admin/commit/759e5320790504f0d274289001543c1397e8b617))
- some color error ([33b2365](https://github.com/anncwb/vue-vben-admin/commit/33b2365f6e645edf2a6c1cf38596aaec52b35df6))
- **description:** not rendering while show method return false ([#253](https://github.com/anncwb/vue-vben-admin/issues/253)) ([23eba27](https://github.com/anncwb/vue-vben-admin/commit/23eba274560a294f50e4b7c529ae8a63a266fb87)), closes [#252](https://github.com/anncwb/vue-vben-admin/issues/252)
- fix collapse header title not rendering ([#256](https://github.com/anncwb/vue-vben-admin/issues/256)) ([c81d48e](https://github.com/anncwb/vue-vben-admin/commit/c81d48e734b09217fa42df2358e616a970006eab))
- **pop-confirm-button:** fix responsive failure [#246](https://github.com/anncwb/vue-vben-admin/issues/246) ([c57dea0](https://github.com/anncwb/vue-vben-admin/commit/c57dea0438fc5ba0fbf1716b9e76e2fba1f33f84))
- fix the problem of mock error under post [#247](https://github.com/anncwb/vue-vben-admin/issues/247) ([9b6f37c](https://github.com/anncwb/vue-vben-admin/commit/9b6f37caef75f8752ea8bd07a78377dcaa59922b))
- suppoer build sourcemap ([3ba8285](https://github.com/anncwb/vue-vben-admin/commit/3ba828558646a7fa233ebbbda27f71c3121dd7c7))
- **type:** fix .vue file type error ([22088e8](https://github.com/anncwb/vue-vben-admin/commit/22088e820c79a9832179c8fb7c5cffe30b9b57e9))
- **upload:** fix maxNumber not work [#240](https://github.com/anncwb/vue-vben-admin/issues/240) ([91e004e](https://github.com/anncwb/vue-vben-admin/commit/91e004e21148c38e572cfbb6b75f0a6f353c15b6))
### Features
- added brotli|gzip compression and related test commands ([993538d](https://github.com/anncwb/vue-vben-admin/commit/993538de21dbb9e54e308afb40ff096ba0ab0e19))
- support echarts 5.0 ([370b12f](https://github.com/anncwb/vue-vben-admin/commit/370b12f5154f4a531c3a27c3ccc2601845872344))
- **modal:** exporse redoModalHeight ([a3a903b](https://github.com/anncwb/vue-vben-admin/commit/a3a903bc86e7248424f94f734d21c86c5327ed20))
### Performance Improvements
- adjust the return value of the interface to obtain user information in array format [#259](https://github.com/anncwb/vue-vben-admin/issues/259) ([5894093](https://github.com/anncwb/vue-vben-admin/commit/589409305f58ebc2f6b110bd7b31f924ecd06c16))
- remove unless code ([2365754](https://github.com/anncwb/vue-vben-admin/commit/23657547ab28fa65c2369ded8e73929dee76c750))
- update style ([aaae668](https://github.com/anncwb/vue-vben-admin/commit/aaae66835a9f1bdfa316e187c01557e5b54959ab))
# [2.0.0-rc.18](https://github.com/anncwb/vue-vben-admin/compare/v2.0.0-rc.17...v2.0.0-rc.18) (2021-02-04)
### Bug Fixes
- **build:** fix rollup compact not work ([783e658](https://github.com/anncwb/vue-vben-admin/commit/783e65813d41ad9a3030412edede6f25f8f8cb49))
- **descriotion:** fix type [#228](https://github.com/anncwb/vue-vben-admin/issues/228) ([4909a4c](https://github.com/anncwb/vue-vben-admin/commit/4909a4cb25ee62661e38cac38a8c3a388fdabbdf))
- **form:** format destructuring assignment error ([#238](https://github.com/anncwb/vue-vben-admin/issues/238)) ([612995a](https://github.com/anncwb/vue-vben-admin/commit/612995a5326ef183d9f454059da6a2914ce5dd2f))
- **menu:** fix the menu outside link does not jump ([55d4b77](https://github.com/anncwb/vue-vben-admin/commit/55d4b77b04d7a87b416a37019fbf047df1eeec41))
- **menu:** top submenu disappeared problem [#214](https://github.com/anncwb/vue-vben-admin/issues/214) ([0ec1a62](https://github.com/anncwb/vue-vben-admin/commit/0ec1a62e596c363f3f017d6ac3b374a1b5caa7c5))
- **modal:** fullscreen height calculation error [#203](https://github.com/anncwb/vue-vben-admin/issues/203) ([b45f8c5](https://github.com/anncwb/vue-vben-admin/commit/b45f8c5021a4225026ed698c083a1af42a08faff))
- **moment:** fix moment error [#217](https://github.com/anncwb/vue-vben-admin/issues/217) ([61cf0f7](https://github.com/anncwb/vue-vben-admin/commit/61cf0f791e8ee05676fe7fa382b6a2c2b1bea92d))
- **ripple:** fix ripple style [#211](https://github.com/anncwb/vue-vben-admin/issues/211) ([2201629](https://github.com/anncwb/vue-vben-admin/commit/22016291e4df206dbca351d00ae033c952276ebe))
- **table:** fix the table: cancel editing and not restore the initial value [#235](https://github.com/anncwb/vue-vben-admin/issues/235) ([1d0ec36](https://github.com/anncwb/vue-vben-admin/commit/1d0ec3629f9cdd40c16b62ce61f9230dcd56a82f))
- modifyVars not work ([b107b52](https://github.com/anncwb/vue-vben-admin/commit/b107b5288695130592a82951012b743fc825880f))
- **optimize-deps:** fix resize-observer-polyfill error ([1fac4b4](https://github.com/anncwb/vue-vben-admin/commit/1fac4b4ba76d432b9a56e142a8d56571e825950f))
- **simple-menu:** collapse openmenus error [#204](https://github.com/anncwb/vue-vben-admin/issues/204) ([ca4f1a8](https://github.com/anncwb/vue-vben-admin/commit/ca4f1a8faf7d588c0d57d0dc81f4dc04cd757380))
- **table:** cell content does not wrap [#210](https://github.com/anncwb/vue-vben-admin/issues/210) ([ea93553](https://github.com/anncwb/vue-vben-admin/commit/ea9355398fe89235bf2e657c291541bd79a41d98))
- **table:** fix the initial data display of editable cells ([#218](https://github.com/anncwb/vue-vben-admin/issues/218)) ([9ea257e](https://github.com/anncwb/vue-vben-admin/commit/9ea257e1fbd9e50369b0065eb4db37d4f9c24970))
- **use-table:** fix types ([c889fb1](https://github.com/anncwb/vue-vben-admin/commit/c889fb174bbd8301479cd67ed99cb5f3552f9988))
- error action style ([da64c1d](https://github.com/anncwb/vue-vben-admin/commit/da64c1dac95b96984283e496070ab9dc086dca4d))
### Features
- production mode compressed image ([de332ae](https://github.com/anncwb/vue-vben-admin/commit/de332ae3f55afa611e86322753d5a713ea00307d))
- theme color switch ([3d1681e](https://github.com/anncwb/vue-vben-admin/commit/3d1681ee9ae2b8e8a8f9d7afeaef3b059aa20b48))
- vite preview ([c1a4600](https://github.com/anncwb/vue-vben-admin/commit/c1a4600b8a0f42c37d90c05198627062eb5742e2))
- **api-select:** added numberToString prop [#200](https://github.com/anncwb/vue-vben-admin/issues/200) ([5d51d48](https://github.com/anncwb/vue-vben-admin/commit/5d51d48787f7b96637bc6abe5175578e0263092a))
### Performance Improvements
- **form:** perf form in modal ([2882d6e](https://github.com/anncwb/vue-vben-admin/commit/2882d6e937a7d4996ae42ff62148d9a2f893fe47))
- **mock:** when mock is not used, move mock.js out of the package file ([43503d5](https://github.com/anncwb/vue-vben-admin/commit/43503d597028926c93e4624d999cad4bbccc75fb))
- **nprocess:** remove nprocess css ([733afdd](https://github.com/anncwb/vue-vben-admin/commit/733afddd19523550d8c7df5c523a0b0929afc608))
### Reverts
- vite previre ([2eb2d2a](https://github.com/anncwb/vue-vben-admin/commit/2eb2d2a07529f7a33d2fbbf1e5fc2e1aac706b0f))
# [2.0.0-rc.17](https://github.com/anncwb/vue-vben-admin/compare/v2.0.0-rc.16...v2.0.0-rc.17) (2021-01-18)
### Bug Fixes
- **menu:** currentActiveMenu fails after refresh [#188](https://github.com/anncwb/vue-vben-admin/issues/188) ([6d5c49f](https://github.com/anncwb/vue-vben-admin/commit/6d5c49f0a208de5b745c36d2320dd4c2cffe7d75))
- **menu-trigger:** menu-trigger lost ([b803c41](https://github.com/anncwb/vue-vben-admin/commit/b803c4100d5b40c04ae4c3b7153f7f8f32d7da81))
- **mitt:** logout and clear the mitt ([0aeec5e](https://github.com/anncwb/vue-vben-admin/commit/0aeec5e9d727fc6291fa2d6edaedb4c3e1ef0dad))
- **table:** index column value error [#187](https://github.com/anncwb/vue-vben-admin/issues/187) ([056fc13](https://github.com/anncwb/vue-vben-admin/commit/056fc131168c4e900e9257c3e03257a390c3d3ba))
- **table:** tableAction icon [#182](https://github.com/anncwb/vue-vben-admin/issues/182) ([b9d53a7](https://github.com/anncwb/vue-vben-admin/commit/b9d53a7133de70922d6f2a0e16e5b623ffab84fb))
### Features
- css import on demand ([c2f6542](https://github.com/anncwb/vue-vben-admin/commit/c2f6542b48abb85b2c80d13a36882899b11c140b))
### Performance Improvements
- auto import mock file ([df6b5e9](https://github.com/anncwb/vue-vben-admin/commit/df6b5e926f3384a1c56e6607a39efcc4638e8dbc))
# [2.0.0-rc.16](https://github.com/anncwb/vue-vben-admin/compare/v2.0.0-rc.15...v2.0.0-rc.16) (2021-01-12)
### Bug Fixes
- **table:** table setting error [#174](https://github.com/anncwb/vue-vben-admin/issues/174) [#165](https://github.com/anncwb/vue-vben-admin/issues/165) ([c960020](https://github.com/anncwb/vue-vben-admin/commit/c9600208c52e3575fe8741e350833f7952bae3b7))
- mock plugin error [#171](https://github.com/anncwb/vue-vben-admin/issues/171) ([3509ebe](https://github.com/anncwb/vue-vben-admin/commit/3509ebec165d26651cc02dc233bd9433c544bed5))
- upload component not work [#169](https://github.com/anncwb/vue-vben-admin/issues/169) ([18ad1bc](https://github.com/anncwb/vue-vben-admin/commit/18ad1bcc6e927f70dc16bf7e3c1627c1f7f376f3))
- useI18n type ([c22de5c](https://github.com/anncwb/vue-vben-admin/commit/c22de5c35b4781322c9ee17ad375ec0af2fe60a7))
- **form:** formAction slot not work ([de5bf75](https://github.com/anncwb/vue-vben-admin/commit/de5bf757f241a097d62d61adf4d7346b73a09f92))
- **layout:** fix layout scale error ([da76f3c](https://github.com/anncwb/vue-vben-admin/commit/da76f3c77bd044caaf65e2c7a5c1c9dd72b4ca44))
- **modal:** height calc error [#161](https://github.com/anncwb/vue-vben-admin/issues/161) ([144ab57](https://github.com/anncwb/vue-vben-admin/commit/144ab577da06ff0bd1f258d1901b87864f232e45))
- **table:** fix edit-table not work ([c031163](https://github.com/anncwb/vue-vben-admin/commit/c031163f34d7ec16aa5a7a406d5467a18e527c79))
- **table:** fix table setting error [#162](https://github.com/anncwb/vue-vben-admin/issues/162) ([a2c89d2](https://github.com/anncwb/vue-vben-admin/commit/a2c89d2e842beb9f15f3fc00d651c42954a57ff7))
- **table:** restore the property of the table ([5c27353](https://github.com/anncwb/vue-vben-admin/commit/5c2735346745cf91aa9812a0afbf62e4625faf40))
- **table:** table columns setting error ([af55511](https://github.com/anncwb/vue-vben-admin/commit/af55511bd6e533ab68356aa9038f80f50f53cf26))
- **table:** table columns setting will uncheck all render columns [#154](https://github.com/anncwb/vue-vben-admin/issues/154) ([aa596af](https://github.com/anncwb/vue-vben-admin/commit/aa596af608a313a5494db8e3ddbf0ef84c7f0c55))
- **table:** table memory overflow ([7a07b70](https://github.com/anncwb/vue-vben-admin/commit/7a07b703d11afb832daa4bd2b87bf5cab3c61e04))
- **transition:** fix transition not work ([a7a8b89](https://github.com/anncwb/vue-vben-admin/commit/a7a8b894c1062d8eb05a094fdbb7887044d0d973))
- invalid error-log page path ([#158](https://github.com/anncwb/vue-vben-admin/issues/158)) ([17ecaea](https://github.com/anncwb/vue-vben-admin/commit/17ecaea97d1d4c61ddb79a23616a49598c9a10aa))
### Features
- **tinymce:** add image upload [#170](https://github.com/anncwb/vue-vben-admin/issues/170) ([3ad1a4f](https://github.com/anncwb/vue-vben-admin/commit/3ad1a4f5a69b4242d55e6bc17aceab7279241e14))
- added mixSide trigger ([1e5fcd2](https://github.com/anncwb/vue-vben-admin/commit/1e5fcd2cd2981b29f06cff08e588077b2dd02f45))
- support vite2 ([eba5576](https://github.com/anncwb/vue-vben-admin/commit/eba55769ec765cd4fbf1faefdd4f3df5e38f11d9))
- **layout:** added setting. Used to fix the left mixed mode menu ([97180e8](https://github.com/anncwb/vue-vben-admin/commit/97180e83f5055ebd138acc2a82c981d8a7399371))
- **menu:** add mixSideTrigger setting ([0419a07](https://github.com/anncwb/vue-vben-admin/commit/0419a070413be34ea5455ed955fa51d8c522da86))
- **modal:** add minHeight and height prop [#156](https://github.com/anncwb/vue-vben-admin/issues/156) ([5091a87](https://github.com/anncwb/vue-vben-admin/commit/5091a875ab520c51aec4c57cdd200d68016958ab))
- **page-wrapper:** added pageWrapper component ([31ff055](https://github.com/anncwb/vue-vben-admin/commit/31ff0559fe3b635fc2091aac0e2f5e340629134c))
- **table:** add summaryData prop [#163](https://github.com/anncwb/vue-vben-admin/issues/163) ([8d7d083](https://github.com/anncwb/vue-vben-admin/commit/8d7d0835adf4a7d1b8afc5e8bd911a60833006a4))
- **tabs:** added tab folding ([0e7c57b](https://github.com/anncwb/vue-vben-admin/commit/0e7c57bd5ecafd8283bcc950b24bb63b59b70e5a))
### Performance Improvements
- perf table ([cdf0a60](https://github.com/anncwb/vue-vben-admin/commit/cdf0a600e505daf429446b8a7968269e1034de04))
- **i18n:** merge common lang ([efbde0d](https://github.com/anncwb/vue-vben-admin/commit/efbde0d57e20d07373d78d1226e2e83f396a74f3))
- add @ant-design/icons-vue to optimizeDeps ([fb57cf7](https://github.com/anncwb/vue-vben-admin/commit/fb57cf734da31af94f3072c685b778a64fc740a5))
- **menu:** mixSideTrigger setting ([#155](https://github.com/anncwb/vue-vben-admin/issues/155)) ([e821f4c](https://github.com/anncwb/vue-vben-admin/commit/e821f4c706c4108a4309a0589223e05e718f15cf))
# [2.0.0-rc.15](https://github.com/anncwb/vue-vben-admin/compare/v2.0.0-rc.14...v2.0.0-rc.15) (2020-12-31)
### Bug Fixes
- **build:** fix environment variable configuration file failure ([bd7b53f](https://github.com/anncwb/vue-vben-admin/commit/bd7b53f14adc05fd3d4af5027b5fb85015021ac9))
- **charts:** fix echarts does not display after refresh [#140](https://github.com/anncwb/vue-vben-admin/issues/140) ([5cbfb2a](https://github.com/anncwb/vue-vben-admin/commit/5cbfb2a1f9ace8b991ac67c5b7d37b64eb2dbac8))
- **demo:** fix demo error ([a0681cc](https://github.com/anncwb/vue-vben-admin/commit/a0681cca8f9de2e3686001fa715f53f6fc3cf1a1))
- **form:** fix appendSchemaByField not work ([405d746](https://github.com/anncwb/vue-vben-admin/commit/405d7466dd935a845e91f4c6ece76b1475507eb7))
- **form:** form validate error ([a305e59](https://github.com/anncwb/vue-vben-admin/commit/a305e59124f4cc88aaf6ec85a13fc998a18b9471))
- **form:** form-item style error ([08df198](https://github.com/anncwb/vue-vben-admin/commit/08df198710ff597af2cbffa2afbb3a6ca13a1d63))
- **iframe:** iframe loads early when closing multi-tabs ([73cee06](https://github.com/anncwb/vue-vben-admin/commit/73cee06daa26c056131fb5ec78afd912dd9832f7))
- **locale:** fix locale.show not work ([10cd4fc](https://github.com/anncwb/vue-vben-admin/commit/10cd4fcdff2fa3961e095285ae7a26b38be52c2a))
- **menu:** fix scrillbar not work ([de25557](https://github.com/anncwb/vue-vben-admin/commit/de25557f86945a96b89294043796ccf4ab476ad5))
- **modal:** do not hide the scroll bar when opening the pop-up window [#151](https://github.com/anncwb/vue-vben-admin/issues/151) ([8f332e3](https://github.com/anncwb/vue-vben-admin/commit/8f332e3cd45814a181a24c884edf050936928755))
- **sider:** mix mode adaptation in the left menu ([ed213d8](https://github.com/anncwb/vue-vben-admin/commit/ed213d878b78697f0bdb69cb474dfab45972b2cb))
- **table:** Update useDataSource.ts ([#131](https://github.com/anncwb/vue-vben-admin/issues/131)) ([877311f](https://github.com/anncwb/vue-vben-admin/commit/877311f9df70b7d76f8a0f8b5082f061de439ec8))
- **table:** wrong tag label style [#134](https://github.com/anncwb/vue-vben-admin/issues/134) ([e09e0a1](https://github.com/anncwb/vue-vben-admin/commit/e09e0a12531977d679ab0f4574f4016d4c5b2ad0))
- **tinymce:** the editor reports an error under keep-alive [#152](https://github.com/anncwb/vue-vben-admin/issues/152) ([09c9f8a](https://github.com/anncwb/vue-vben-admin/commit/09c9f8a881d1f2c76b11fdeff08f3ca2893e0886))
- **types:** fix routing type error [#145](https://github.com/anncwb/vue-vben-admin/issues/145) ([b6e5c3f](https://github.com/anncwb/vue-vben-admin/commit/b6e5c3f625f3e30b1fa7433e57b1294a8ce8d04b))
- add an example of markdown embedded in the form [#138](https://github.com/anncwb/vue-vben-admin/issues/138) ([7db0c5c](https://github.com/anncwb/vue-vben-admin/commit/7db0c5c49f23a4ab4958b3f73d47516deafa6166))
### Features
- **breadcrumb:** add breadcrumb demo [#143](https://github.com/anncwb/vue-vben-admin/issues/143) ([819bcbe](https://github.com/anncwb/vue-vben-admin/commit/819bcbe5263c721f1f77cb277d670a9868b229f7))
- **hook:** add useKeyPress ([3c3e640](https://github.com/anncwb/vue-vben-admin/commit/3c3e640d69b48d8e9382acd25b60d906af038a9d))
- add mainout page demo ([930383f](https://github.com/anncwb/vue-vben-admin/commit/930383f9ae17b18d697a35ef9c73ad17dbca1e13))
- **layout:** add mix sidebar mode ([e6db0d3](https://github.com/anncwb/vue-vben-admin/commit/e6db0d39b9ba98f6396866715ed3b6d56994697a))
- add ripple directive ([2e79c9f](https://github.com/anncwb/vue-vben-admin/commit/2e79c9f37adda4003e6b054561b26da69a762673))
### Performance Improvements
- **form:** improve the form function ([ac1a369](https://github.com/anncwb/vue-vben-admin/commit/ac1a36950259844822c6300a00710b040dfc2640))
- **import:** perf components import ([2ee01fa](https://github.com/anncwb/vue-vben-admin/commit/2ee01fa6ea3200ec964d4e1b4765e48dfa7aeb3a))
- **modal-drawer:** replace the scrollbar assembly ([ebf7c8a](https://github.com/anncwb/vue-vben-admin/commit/ebf7c8aa53b7ed11c72734646d558a559e818473))
- **route:** refactor guard ([3b126e0](https://github.com/anncwb/vue-vben-admin/commit/3b126e011c7ca7ac1b008c37aa2cf617242a2e9c))
- Update useApexCharts.ts ([#139](https://github.com/anncwb/vue-vben-admin/issues/139)) ([5eecec0](https://github.com/anncwb/vue-vben-admin/commit/5eecec03126d131bd1210d4fcac3acfe3d5aeb40))
# [2.0.0-rc.14](https://github.com/anncwb/vue-vben-admin/compare/2.0.0-beta.3...v2.0.0-rc.14) (2020-12-15)
### Bug Fixes
- **form:** fix the form item setting not taking effect ([6936adb](https://github.com/anncwb/vue-vben-admin/commit/6936adb2c2af3c0bfbd238be1d61933601ff2b88))
- **router:** reserving `Redirect` after reset ([#126](https://github.com/anncwb/vue-vben-admin/issues/126)) ([ec7efcf](https://github.com/anncwb/vue-vben-admin/commit/ec7efcf0f0161c8e14168bf69ba27ba36e2a1ac8))
- fix modal and drawer component missing uid ([1293a73](https://github.com/anncwb/vue-vben-admin/commit/1293a7389ea797b1c1dad62e06657c846b1dcb3c))
- **comp:** fix the memory overflow problem of component containing keywords ([6b3195b](https://github.com/anncwb/vue-vben-admin/commit/6b3195b4ca88a33044bcd014e8c5d090710e7fbb))
- **form:** fix baseColProps not work ([c8ef82b](https://github.com/anncwb/vue-vben-admin/commit/c8ef82b2c11c9938f0f7a7f6a1a10010b82979dc))
- **form:** fix form inputNumber verification error ([4ddee05](https://github.com/anncwb/vue-vben-admin/commit/4ddee05dee87c944ba95dca54a754e048b8cfc84))
- **form:** fix form verification and console error message issues ([bb1b267](https://github.com/anncwb/vue-vben-admin/commit/bb1b267e2fc306608300ec09084b1f3d0cab7e59))
- **icon:** fix g-icon not work ([f7ec3c9](https://github.com/anncwb/vue-vben-admin/commit/f7ec3c931e780b2b5d35bf65ea5b4ace26f7c356))
- **keep-alive:** fix the problem that the multi-level routing cache page is rendered multiple times [#123](https://github.com/anncwb/vue-vben-admin/issues/123) ([0daca28](https://github.com/anncwb/vue-vben-admin/commit/0daca28362419911d642e4b3a5111e213eef49d9))
- **login:** fix the problem of successful login and notify disappearing ([0434030](https://github.com/anncwb/vue-vben-admin/commit/0434030f2777ee65a4255287e1842fcb0b772f87))
- **menu:** calc 0 不能省略单位 ([#124](https://github.com/anncwb/vue-vben-admin/issues/124)) ([d023fb1](https://github.com/anncwb/vue-vben-admin/commit/d023fb13742cc1f5cc1585b82f1a7b3c576ee66c))
- **menu:** fix externalLink not work ([7bae4c3](https://github.com/anncwb/vue-vben-admin/commit/7bae4c37525c6534ec0b0c3ea8c1b2257af74a33))
- **menu:** fix menu icon style ([1bc237d](https://github.com/anncwb/vue-vben-admin/commit/1bc237d77a068e99b0e803ab4f16d8bbcf54ff6b))
- **menu:** fix menu split mode problem ([1ef49e5](https://github.com/anncwb/vue-vben-admin/commit/1ef49e542d23ca44696ec5dd2f6498a4ea8135aa))
- **theme:** css filter breaking fixed position ([#125](https://github.com/anncwb/vue-vben-admin/issues/125)) ([c911af4](https://github.com/anncwb/vue-vben-admin/commit/c911af4aca49e6f9fe099e74a4d454286554e181))
- 整体图标调整 ([5dc8226](https://github.com/anncwb/vue-vben-admin/commit/5dc8226ce14559f48f8b979809f8a054ce7935e5))
- file upload key loss [#120](https://github.com/anncwb/vue-vben-admin/issues/120) ([29461a8](https://github.com/anncwb/vue-vben-admin/commit/29461a856826fbb7726848982387ea78f8573754))
- **menu:** fix the calculation error of the top menu width ([de1f006](https://github.com/anncwb/vue-vben-admin/commit/de1f00628479c4d31e6ed904d4b0fd7e312cc030))
- **table:** fix table setting error ([59ad824](https://github.com/anncwb/vue-vben-admin/commit/59ad82442bf213bac547940086ff4e14d0cd342a))
- **table:** fix unsuccessful saving of row edit table ([#117](https://github.com/anncwb/vue-vben-admin/issues/117)) ([404db2f](https://github.com/anncwb/vue-vben-admin/commit/404db2fb4975c69851dbf73a9ea8f981fb0ddb56))
- **upload:** fix file upload key loss [#120](https://github.com/anncwb/vue-vben-admin/issues/120) ([fb5395b](https://github.com/anncwb/vue-vben-admin/commit/fb5395b5401b4b1f9e605d2721784482a76d49cc))
- **upload:** repair file upload and delete invalidation ([bd6b203](https://github.com/anncwb/vue-vben-admin/commit/bd6b203fa969d173574657940a50b649c778b0b4))
- fix cssVar hmr error ([2b95be8](https://github.com/anncwb/vue-vben-admin/commit/2b95be8013e70e1b891601cecb6d9e03a56d1ac2))
- fix descriotions title not work ([819127e](https://github.com/anncwb/vue-vben-admin/commit/819127e807123cccc7ae50f0fdffb43a662465d4))
- fix form submit error ([94bf854](https://github.com/anncwb/vue-vben-admin/commit/94bf854dd98f37ffb39e9086c565a0610c250205))
- fix form validate error ([1db72c8](https://github.com/anncwb/vue-vben-admin/commit/1db72c8fe13384f24e9cc1bdc839d5e4176ea9b4))
- fix keepAlive not work ([b884654](https://github.com/anncwb/vue-vben-admin/commit/b884654761f93455014fd1dcb0e40c030d8fb360))
- fix menu style not work ([bda3e5d](https://github.com/anncwb/vue-vben-admin/commit/bda3e5da30b434dd3a5879695261422fdd365455))
- fix mock data error [#109](https://github.com/anncwb/vue-vben-admin/issues/109) ([41a4b82](https://github.com/anncwb/vue-vben-admin/commit/41a4b827a22e785453238da6b9b8b5b1c604b91a))
- fix notify type error ([cb1ae34](https://github.com/anncwb/vue-vben-admin/commit/cb1ae34f1120d2555ff039fc945235c3f45e13a8))
- fix spelling errors of i18n words ([68a96b7](https://github.com/anncwb/vue-vben-admin/commit/68a96b7f81a1ad72c93a53c2ebfde046c66c215f))
- fix spin style ([fca0bb1](https://github.com/anncwb/vue-vben-admin/commit/fca0bb164a0f2e03acb5090bf59634225f5c06ee))
- fix table column settings not displayed by setting ([54d1405](https://github.com/anncwb/vue-vben-admin/commit/54d14056462566521f2528480c13fb24279156ae))
- fix the display problem of table icon ([de499a1](https://github.com/anncwb/vue-vben-admin/commit/de499a145556427304abe075b62e6869f44dc640))
- fix the original page after login expired ([6676c95](https://github.com/anncwb/vue-vben-admin/commit/6676c9506be7b3095c466c83432d40b2a36565fb))
- fix win system dynamicImport error ([a90d93f](https://github.com/anncwb/vue-vben-admin/commit/a90d93fc4d8dd8491702183f3db700c33dbcc5a8))
- page switching did not return to the top ([fef3644](https://github.com/anncwb/vue-vben-admin/commit/fef3644067b7ccac96ec9ae122e3f1c8b8fc58ef))
- pageLoading not working ([3f78b5a](https://github.com/anncwb/vue-vben-admin/commit/3f78b5aa0cd3e7a6f17d58512ca93ee2905d5e2f))
- style error ([7bfe5f7](https://github.com/anncwb/vue-vben-admin/commit/7bfe5f753d77620027248a6238bccd8a23f7ad7c))
- **charts:** fix useCharts resize not work ([6d9585b](https://github.com/anncwb/vue-vben-admin/commit/6d9585b46f849ea4cf3dc93d46f15c2c09d04891))
- **form:** fix updateSchema error [#100](https://github.com/anncwb/vue-vben-admin/issues/100) ([4982786](https://github.com/anncwb/vue-vben-admin/commit/498278660112a52b7c6e608159d20920d6047e04))
- 修复链接 ([#49](https://github.com/anncwb/vue-vben-admin/issues/49)) ([28392c3](https://github.com/anncwb/vue-vben-admin/commit/28392c3d6efc2fb3298255bc2c466167e8a4e91c))
- fix editable cells cannot be entered ([4500214](https://github.com/anncwb/vue-vben-admin/commit/4500214b2a158965281e43e673622e4492e8ca26))
- fix expandTransition ([3355066](https://github.com/anncwb/vue-vben-admin/commit/335506628e15e29e08df55d4b7e7cf6333fe25be))
- fix fullscreen bg color not work ([#75](https://github.com/anncwb/vue-vben-admin/issues/75)) ([0c28ffa](https://github.com/anncwb/vue-vben-admin/commit/0c28ffa8e6a93e8923b7d3a32292db8ae786242c))
- **table:** fix table typo ([69af37e](https://github.com/anncwb/vue-vben-admin/commit/69af37ec88e21acf926fdf5969c2189dc7450822))
- fix menu permission failure ([b8353fe](https://github.com/anncwb/vue-vben-admin/commit/b8353fe1f262b87cc20af56aaf380ae1a5599724))
- fix message type error ([35d2bfc](https://github.com/anncwb/vue-vben-admin/commit/35d2bfc5623fcf3a608ae12e9781b2e23ff4130d))
- fix the problem of closing multiple tabs ([275ad9f](https://github.com/anncwb/vue-vben-admin/commit/275ad9f14e8fa75620ff35c906c06c616fb2104f))
- **mock:** fix mock paging tool error ([b36d948](https://github.com/anncwb/vue-vben-admin/commit/b36d9486a544dd3badea23d86088af98aadad8f4))
- **table:** fix table search criteria collapse failure ([84b8302](https://github.com/anncwb/vue-vben-admin/commit/84b8302c0921ea7fbcd1c42fa057b94660129857))
- fix missing cache of refresh page ([02d6a39](https://github.com/anncwb/vue-vben-admin/commit/02d6a3940277a5939d25d16fda58e09346821e0e))
- fix npm build error ([a3b7a65](https://github.com/anncwb/vue-vben-admin/commit/a3b7a6537ae25af076fdcccb50dd6967f0def40b))
- fix table small style ([#67](https://github.com/anncwb/vue-vben-admin/issues/67)) ([da4aea1](https://github.com/anncwb/vue-vben-admin/commit/da4aea1399f67759b06266aa410036f69fde9521))
- **table:** fix table type error ([05980a8](https://github.com/anncwb/vue-vben-admin/commit/05980a817e68c2a57eed2db7cf23bd7eb4ec10ba))
- build error ([7bd0b8e](https://github.com/anncwb/vue-vben-admin/commit/7bd0b8eb6ffb143b4f341efeeb60b4e90f0e4ddf))
- fix abnormal breadcrumb status ([144fde8](https://github.com/anncwb/vue-vben-admin/commit/144fde8a688217440071c7b0ac70e46f6832635a))
- fix base-help style not work ([1fb759e](https://github.com/anncwb/vue-vben-admin/commit/1fb759ec7cf2c6104670025073920ca352413b10))
- fix drawer autoHeight ([88de82c](https://github.com/anncwb/vue-vben-admin/commit/88de82c493b068b6d9bb5e29475350ed092fe482))
- fix missing page refresh parameters ([349d197](https://github.com/anncwb/vue-vben-admin/commit/349d1978b154f6e9e74e36de7cc56a2ca261d0b0))
- fix modal dragging failure when destroyOnClose=true ([#51](https://github.com/anncwb/vue-vben-admin/issues/51)) ([9c02d8e](https://github.com/anncwb/vue-vben-admin/commit/9c02d8ec08b309e7f982f417a4c907f33ccc96f0))
- fix npm script ([b84de1a](https://github.com/anncwb/vue-vben-admin/commit/b84de1a515600d2ead1c2b5f6db949e7bf6ab923))
- fix require error ([06e1d38](https://github.com/anncwb/vue-vben-admin/commit/06e1d3879be187f99f5142e054884e1c09ac8dfa))
- fix routing switch, tab is not activated ([beb4c3a](https://github.com/anncwb/vue-vben-admin/commit/beb4c3a37f314b97657a1d85e7db2abf40dbe6c3))
- fix script preview no build ([c2333f5](https://github.com/anncwb/vue-vben-admin/commit/c2333f5d044c74c9df82c6c3134681ba21e0d0cd))
- fix table auto height ([ddc3786](https://github.com/anncwb/vue-vben-admin/commit/ddc3786b168a2931200ef61cc68dd80a18d714cc))
- fix the failure of table expansion icon animation ([8e885d6](https://github.com/anncwb/vue-vben-admin/commit/8e885d6967747f3204e61ca85bde25ac2b8ba2a4))
- fix the failure of table expansion icon animation ([db06289](https://github.com/anncwb/vue-vben-admin/commit/db06289481965524f42ed36a056bd54ba1a46dfe))
- fix the problem of folding display name of the first level menu ([e3cbc93](https://github.com/anncwb/vue-vben-admin/commit/e3cbc9326ecedf386919f344df5dbdef8eb3d78c))
- fix the problem of page blank caused by page refresh ([7653610](https://github.com/anncwb/vue-vben-admin/commit/7653610c7bc45e97cb744994835cf7fb5074ff7b))
- fix the style problem of the table border in the production environment ([f2c7638](https://github.com/anncwb/vue-vben-admin/commit/f2c7638bd7789bddacd56ea2ab809f4a0b3b86cb))
- fix the top menu adaptive failure ([2f12556](https://github.com/anncwb/vue-vben-admin/commit/2f12556d26ba386d9dca2ecf8a88e3764abab870))
- fix window npm script ([a0b09e7](https://github.com/anncwb/vue-vben-admin/commit/a0b09e74baf1f4e514da85ed9b1859ca2820fb37))
- form col style ([840332a](https://github.com/anncwb/vue-vben-admin/commit/840332abf733dd1dc404523d38c5377114f4b6c2))
- some error ([2407b33](https://github.com/anncwb/vue-vben-admin/commit/2407b3368c3fc5128bbfced98a1d2c70fa3e02e0))
- **modal:** fix modal not showing footer ([fb0c776](https://github.com/anncwb/vue-vben-admin/commit/fb0c7763eddde38d3746cb424ebe9662ac576c86))
- **tree:** fix tree style ([#99](https://github.com/anncwb/vue-vben-admin/issues/99)) ([e8ccdc7](https://github.com/anncwb/vue-vben-admin/commit/e8ccdc7f34891ea31768aea9ebcfc33227d37eb7))
- **use-redo:** refresh the page to keep the parameters([#104](https://github.com/anncwb/vue-vben-admin/issues/104)) ([e04aaa0](https://github.com/anncwb/vue-vben-admin/commit/e04aaa06459c6613e59aa6ae5906b998b0685bdb))
- fix the disappearance of tab switching parameters ([#56](https://github.com/anncwb/vue-vben-admin/issues/56)) ([6bffdb5](https://github.com/anncwb/vue-vben-admin/commit/6bffdb5c64aa139cf6119b50aeed42629a65f07b))
- fix the occupancy problem of the folding button ([#90](https://github.com/anncwb/vue-vben-admin/issues/90)) ([cd35d3e](https://github.com/anncwb/vue-vben-admin/commit/cd35d3e0d16cb57cb15c2ca20c8a663f21e4bfbf))
- fix the problem of collapsed display when the menu has no child nodes ([5cff73b](https://github.com/anncwb/vue-vben-admin/commit/5cff73bcafc27a36f111949d33f463dd2bb52571))
- fix topMenu align not work ([25d43a5](https://github.com/anncwb/vue-vben-admin/commit/25d43a5f7c9182f2ca620f1daf0d5f47d2e4fb2d))
- fix useTimeoutFn not work ([b49950a](https://github.com/anncwb/vue-vben-admin/commit/b49950a3906de6626eedb973590d02e4d95b98b9))
- hmr multiple registered components ([7a6181e](https://github.com/anncwb/vue-vben-admin/commit/7a6181e8c72cd110cdfc09f624f8be43e76ef74c))
- repair local development post request proxy to https error problem ([#63](https://github.com/anncwb/vue-vben-admin/issues/63)) ([34c09fc](https://github.com/anncwb/vue-vben-admin/commit/34c09fcea82e3529519a5acc563a22adcd5faae1))
- repair packaging error ([526e6ce](https://github.com/anncwb/vue-vben-admin/commit/526e6ce22bf15cd04a09faf53a08ac43da491534))
- Repair tree component click to select ([#33](https://github.com/anncwb/vue-vben-admin/issues/33)) ([67df9b8](https://github.com/anncwb/vue-vben-admin/commit/67df9b8c93a26b0edb4f3d5d5c589d355803cea0))
- replace taskfile module ([e828baa](https://github.com/anncwb/vue-vben-admin/commit/e828baa67b5f8e6fa28354d85563d127b6b70d6b))
- reset back to default value after fixing form query ([1c075a7](https://github.com/anncwb/vue-vben-admin/commit/1c075a7a32dd05454bc45d4eb686e2234c3c6175))
- the action column appears repeatedly in the table ([#53](https://github.com/anncwb/vue-vben-admin/issues/53)) ([74d4742](https://github.com/anncwb/vue-vben-admin/commit/74d47424069c4dca71579637916431aa80014fd8))
- the login tab page in tabs ([#60](https://github.com/anncwb/vue-vben-admin/issues/60)) ([bfac425](https://github.com/anncwb/vue-vben-admin/commit/bfac425d1e12943b55e9afb732a36d84f6a02404))
- the useMessage icon style problem ([a2c413a](https://github.com/anncwb/vue-vben-admin/commit/a2c413a838bb3f737e28e95302ccf0a0171c91b6))
- type error ([ecfb702](https://github.com/anncwb/vue-vben-admin/commit/ecfb702b09e296efd5bf095d65840147d47b7923))
- typo ([7658f4d](https://github.com/anncwb/vue-vben-admin/commit/7658f4d6e82dc532b378ec13157756f0e1cd78de))
- update account page demo ([#92](https://github.com/anncwb/vue-vben-admin/issues/92)) ([9f8796e](https://github.com/anncwb/vue-vben-admin/commit/9f8796ee586a5f33e20713f53d2aa447b6aa312e))
- update upload component ([815250e](https://github.com/anncwb/vue-vben-admin/commit/815250ed341ccaec23e7ea34db6cc478a47ad065))
- **excel:** update excel demo ([a207caf](https://github.com/anncwb/vue-vben-admin/commit/a207cafec98461b39882f352f2bf5c7d3c21716a))
- **table:** fix table actionColOptions not work ([5a6db8c](https://github.com/anncwb/vue-vben-admin/commit/5a6db8c640376ca67b451a9647b9958946e5c3ab))
- **table:** fix table type error ([db0bfc8](https://github.com/anncwb/vue-vben-admin/commit/db0bfc886314b193e7cb86a80b6c13b2743aa652))
- **table:** fix the problem that multi-level header configuration does not take effect ([cdf2c59](https://github.com/anncwb/vue-vben-admin/commit/cdf2c59e5c3b070d039c04fb746b53147f5e0ced))
- **tinymce:** fixed multiple editors showing only one ([#83](https://github.com/anncwb/vue-vben-admin/issues/83)) ([1093ec3](https://github.com/anncwb/vue-vben-admin/commit/1093ec3e6e4fe1f49b7458c29e518744fe56532f))
### Features
- add account center page ([#86](https://github.com/anncwb/vue-vben-admin/issues/86)) ([78d4d41](https://github.com/anncwb/vue-vben-admin/commit/78d4d41c85f5341bb5dfd2a1cbb6e60d6858b084))
- add accountSetting page ([#85](https://github.com/anncwb/vue-vben-admin/issues/85)) ([7ad4cee](https://github.com/anncwb/vue-vben-admin/commit/7ad4cee79ade617a13358f7417ce3e1182c1027f))
- add basic-list page ([2f75a94](https://github.com/anncwb/vue-vben-admin/commit/2f75a948899713e10b200e0f39a48d4b62ef231e))
- add card-list page ([3a132f3](https://github.com/anncwb/vue-vben-admin/commit/3a132f3f4f4e08b4675c157548aa093b3a1c3c94))
- add collapsedShowTitle setting ([5737e47](https://github.com/anncwb/vue-vben-admin/commit/5737e478f671e7f1c60f7db08a0007f154b6f4b8))
- add count-to component and demo ([afc7263](https://github.com/anncwb/vue-vben-admin/commit/afc7263efb90c0410041358a9dd5f10ec685ac2f))
- add design setting ([bae53f3](https://github.com/anncwb/vue-vben-admin/commit/bae53f3e2c62b3fca246432307f45a6363c4c176))
- add error handle ([7101587](https://github.com/anncwb/vue-vben-admin/commit/7101587b9676c91e9079044a096df08848f1f602))
- add file download demo ([db3092d](https://github.com/anncwb/vue-vben-admin/commit/db3092db2eb7d5346778847757adb2b9c4041ed5))
- add lazyContainer comp and demo ([fdeaa00](https://github.com/anncwb/vue-vben-admin/commit/fdeaa00bf24b0710ca341fafba8327c786ab9879))
- add markdown component ([5fb069f](https://github.com/anncwb/vue-vben-admin/commit/5fb069f432799e0d17a7102fae70757e320dc0c5))
- add notice ([#47](https://github.com/anncwb/vue-vben-admin/issues/47)) ([7a1e94c](https://github.com/anncwb/vue-vben-admin/commit/7a1e94c49d546e155d8c17b492ff6b1e5fb55121))
- add permissionCacheType setting ([26b6109](https://github.com/anncwb/vue-vben-admin/commit/26b6109ca08a28c37355474bf8593f2e2b741ef6))
- add pwa ([a1b9902](https://github.com/anncwb/vue-vben-admin/commit/a1b9902b97da03d0ee1e99a021fc6497b8f51fa6))
- add README.en-US.md ([#37](https://github.com/anncwb/vue-vben-admin/issues/37)) ([7437896](https://github.com/anncwb/vue-vben-admin/commit/74378960345e706b45fab1f39fba045a1e95a547))
- add result page demo ([21e0548](https://github.com/anncwb/vue-vben-admin/commit/21e0548e34cf70ebf97967089f458e759ca326d9))
- add search page ([dddda5b](https://github.com/anncwb/vue-vben-admin/commit/dddda5b296025d1d6b37ec15930a02722b8e1b0c))
- add search-list page ([4cb3784](https://github.com/anncwb/vue-vben-admin/commit/4cb3784f13fc516c6343798e8bf8a435e14d774c))
- add tab drag and drop sort ([cedba37](https://github.com/anncwb/vue-vben-admin/commit/cedba37e4cf63456c97f7e391761f176137e0165))
- add table setting ([8b3a4d3](https://github.com/anncwb/vue-vben-admin/commit/8b3a4d37a8addd151b918cf64bce6361376dec9e))
- add tag display to the menu ([a3887f8](https://github.com/anncwb/vue-vben-admin/commit/a3887f8cd99546cde8882d77271cc430eb7a83f5))
- add the parameter sortFn to the table ([491ba9a](https://github.com/anncwb/vue-vben-admin/commit/491ba9a3cc19ceb97dd9a6448831b64c86e1e475))
- add the parameter submitOnReset to the form ([#54](https://github.com/anncwb/vue-vben-admin/issues/54)) ([d09406e](https://github.com/anncwb/vue-vben-admin/commit/d09406e3cb8cfc069ce79b5f4194f7d959f63daf))
- add tinymce embedded form example ([58f988a](https://github.com/anncwb/vue-vben-admin/commit/58f988a7184dd7bdec415627e16b56b80f36b661))
- add useDesign ([74e62cb](https://github.com/anncwb/vue-vben-admin/commit/74e62cbc712bdd4d4826e5fe80f537d87e44ffce))
- added base64 file stream download ([a161bfa](https://github.com/anncwb/vue-vben-admin/commit/a161bfa818cb63d9cc0b00ae062eb16b1efaf74f))
- auto import route ([8a1bfdf](https://github.com/anncwb/vue-vben-admin/commit/8a1bfdf13de966acc5eb41718ccb085d3efc4581))
- axios add joinTime field ([f646e37](https://github.com/anncwb/vue-vben-admin/commit/f646e37754d21ba7c89437176bd9e375924dee03))
- first screen loading waiting animation ([4811cce](https://github.com/anncwb/vue-vben-admin/commit/4811cce809453df78dc2c25cd9805eae483297fc))
- global loading add text ([4f98978](https://github.com/anncwb/vue-vben-admin/commit/4f98978edacbe72610a226267628ab20b57cfc4e))
- integrate upload components into form by default ([be2b8a7](https://github.com/anncwb/vue-vben-admin/commit/be2b8a7e175033dace7a521ab26cd319c5cfdea6))
- multi-language component ([dc09de1](https://github.com/anncwb/vue-vben-admin/commit/dc09de1e052d6b104c5af3a426af6b0e7bb147c7))
- multi-language layout ([e5f8ce3](https://github.com/anncwb/vue-vben-admin/commit/e5f8ce3fd8ec25c6fdb122867cd33e4e84a6f43f))
- multi-language support ([1901129](https://github.com/anncwb/vue-vben-admin/commit/19011296ed61f820356f6b201cbb274d57dcb7d3))
- new menu and top bar color selection color matching ([7692ffb](https://github.com/anncwb/vue-vben-admin/commit/7692ffb95b94672b6fbc8c25fd43d9dd1a1da81e))
- projectSetting add closeMessageOnSwitch and removeAllHttpPending ([e83cb06](https://github.com/anncwb/vue-vben-admin/commit/e83cb06bb93544369c8934d1065bf46835e3f003))
- restore the breadcrumb display icon function ([f65bed7](https://github.com/anncwb/vue-vben-admin/commit/f65bed72ac8c63aaed640d59703f73e83de80da5))
- right-click menu supports multiple levels ([f645680](https://github.com/anncwb/vue-vben-admin/commit/f645680a3b9a1f75395329970551d9e5d6bd845b))
- routes with parameters can be cached ([90b3fab](https://github.com/anncwb/vue-vben-admin/commit/90b3fab28ef53135f3cab1f69a4675f98a130857))
- support mobile layout adaptation ([c774a6d](https://github.com/anncwb/vue-vben-admin/commit/c774a6d3a03d9507a9023d600aa9dd9592f52fb3))
- support vscode i18n-ally plugin ([962f90d](https://github.com/anncwb/vue-vben-admin/commit/962f90de445d7935ad76ea7b74a98f12ce9a7498))
- the cache can be configured to be encrypted ([234c1d1](https://github.com/anncwb/vue-vben-admin/commit/234c1d1fae6a7f2c78e456f992f91622ca599060))
- **analysis:** add analysis page ([52ee35c](https://github.com/anncwb/vue-vben-admin/commit/52ee35c4beca8fc07737aa28328663e86ba797d4))
- **breadcrumb:** support showIcon ([#48](https://github.com/anncwb/vue-vben-admin/issues/48)) ([d8b25b4](https://github.com/anncwb/vue-vben-admin/commit/d8b25b488ba4c6626d3b94ed84270e96f403d859))
- **chart:** add useEcharts and useApexChart demo ([21d0ed9](https://github.com/anncwb/vue-vben-admin/commit/21d0ed92dffd28f45c98afee547d25d9b40dde7f))
- **desc-page:** add desc page demo ([7a00036](https://github.com/anncwb/vue-vben-admin/commit/7a000366b92b942727dd2cd7c0aec193f8c1a7b0))
- **excel:** import/export ([#40](https://github.com/anncwb/vue-vben-admin/issues/40)) ([c0692b0](https://github.com/anncwb/vue-vben-admin/commit/c0692b0f43b50be56e399c4aa07c0c4244080e9f))
- **form:** support function type of form item ([5832ee6](https://github.com/anncwb/vue-vben-admin/commit/5832ee6697e23afefc25ba2aa4df9476b5034bf4))
- **form-page:** add form page demo ([0b6110a](https://github.com/anncwb/vue-vben-admin/commit/0b6110a8fc92a11df6501346e093246a5abe2b0e))
- **from:** add required in schema ([2859067](https://github.com/anncwb/vue-vben-admin/commit/28590676214b1c5fdbf6878e40da45a7bc0c5874))
- **tinymce:** add line height ([#58](https://github.com/anncwb/vue-vben-admin/issues/58)) ([adffefd](https://github.com/anncwb/vue-vben-admin/commit/adffefd702688ba5fa8c5df616b8f3685a0fb778))
- **tinymce:** add rich editor ([c0e4c9e](https://github.com/anncwb/vue-vben-admin/commit/c0e4c9e5a55524840e9598d24d84dcada8b57102))
- **transition:** add transition comp and demo ([3713487](https://github.com/anncwb/vue-vben-admin/commit/3713487c85f4b512ab3e13fcb4c89a14b9ee8d50))
- **trigger:** add trigger config ([4f6b65b](https://github.com/anncwb/vue-vben-admin/commit/4f6b65b8a1b7e694718b4aa42aced1e59e90ec9e))
- the Button component extends the and attributes ([8f5016e](https://github.com/anncwb/vue-vben-admin/commit/8f5016e3f3476539a763162ea235cf2aac230eea))
- the production environment can be dynamically configured ([bb3b8f8](https://github.com/anncwb/vue-vben-admin/commit/bb3b8f817de15d336968354515649f7142cd5683))
- **workbench:** add workbench page ([1cd75fc](https://github.com/anncwb/vue-vben-admin/commit/1cd75fcf5ba7a3114399db8f22cf8eb6f2e4d783))
### Performance Improvements
- **setting-drawer:** perf setting-drawer ([ed41e50](https://github.com/anncwb/vue-vben-admin/commit/ed41e5082fd2e6109c2ad3ff77199d15ac14342a))
- **tabs:** perf multiple-tabs ([f81c401](https://github.com/anncwb/vue-vben-admin/commit/f81c401959dda4b8d568c00786b691c21abbb59c))
- **tabs:** perf multiple-tabs ([27e50b4](https://github.com/anncwb/vue-vben-admin/commit/27e50b47479af8eaeb4be020aeb0fcbdb4308295))
- Add the style injection of the top row to the form. ([#102](https://github.com/anncwb/vue-vben-admin/issues/102)) ([b9d3d60](https://github.com/anncwb/vue-vben-admin/commit/b9d3d60e0f8fe1166a0addcc8295365cbe65a7bf))
- adjust the logic of ([b350098](https://github.com/anncwb/vue-vben-admin/commit/b350098f442be1b8143b44e09e735179676f755c))
- code style ([f96d6b2](https://github.com/anncwb/vue-vben-admin/commit/f96d6b221c7ad97e0ed80250acb192b6be92c4a6))
- enhance openModal and openDrawer ([b6d5e5c](https://github.com/anncwb/vue-vben-admin/commit/b6d5e5c96f89c31d4df11e71f2d4cb5ecf8f0b92))
- layout code adjustment ([4392917](https://github.com/anncwb/vue-vben-admin/commit/439291746fe237410140575be2a634a74e8ef382))
- layout style optimization ([7702832](https://github.com/anncwb/vue-vben-admin/commit/77028321816f00799cc3f70d3f0d6bde27c34522))
- mobile style adjustment ([1899146](https://github.com/anncwb/vue-vben-admin/commit/1899146f71ab2020dc01bd84b282e6b614ad3d57))
- optimize lazy loading components ([87fcd0d](https://github.com/anncwb/vue-vben-admin/commit/87fcd0d21ea78ce916a4f2b9cdcceda5e7866eee))
- optimize multiple-tab switching effect ([f2bdf0b](https://github.com/anncwb/vue-vben-admin/commit/f2bdf0b86dd818f3cc59fdb0c55eb1b53b222f7f))
- optimize preview and ContextMenu functions ([bbfb06f](https://github.com/anncwb/vue-vben-admin/commit/bbfb06f0ad1e345b0e716da730acaf7c0a778e4b))
- optimize settingDrawer code ([4ff6b73](https://github.com/anncwb/vue-vben-admin/commit/4ff6b73c2bb57764db2bcd8212d82f028e25e36d))
- optimize tab switching speed ([4baf90a](https://github.com/anncwb/vue-vben-admin/commit/4baf90a5c87493939830129efaa146624faabbcc))
- optimize the size of the first screen ([968f791](https://github.com/anncwb/vue-vben-admin/commit/968f791f4b7112730813c8c990379051c3f8340d))
- optimized page switching effect ([5f2a927](https://github.com/anncwb/vue-vben-admin/commit/5f2a927cd50a5efe4c9576528d944553c5243277))
- perf component ([73c8e0c](https://github.com/anncwb/vue-vben-admin/commit/73c8e0c1583afa83353ff36d1d9ec847776d3016))
- perf context menu ([6e03e05](https://github.com/anncwb/vue-vben-admin/commit/6e03e05032474c858151b3835eb5318486a56729))
- perf excel comp code ([eecde4c](https://github.com/anncwb/vue-vben-admin/commit/eecde4c7e947cf392dbd8eace2db8ed9aea417b1))
- perf loading logic ([f4621cc](https://github.com/anncwb/vue-vben-admin/commit/f4621cc66411d8ff4ca852b548a79cd3da9be1ce))
- perf menu ([88f4a3f](https://github.com/anncwb/vue-vben-admin/commit/88f4a3f02a0c0f35953c93427fe700d414b6ec50))
- perf menu mini style ([66acb21](https://github.com/anncwb/vue-vben-admin/commit/66acb21edda3fcac61849c7c03c6b396992d8d06))
- perf modal and drawer ([81baf1d](https://github.com/anncwb/vue-vben-admin/commit/81baf1d5c4606aab83c0e65397ce4b090c2e4e08))
- tsx use useExpose ([9bb7514](https://github.com/anncwb/vue-vben-admin/commit/9bb751475dc212d4e2829468cf1a11502137071e))
- **button:** delete the button component useless code ([bdce845](https://github.com/anncwb/vue-vben-admin/commit/bdce84537aa58b9507744a3a14c8d598e88e95fc))
- **drawer:** perf drawer ([28f7f7b](https://github.com/anncwb/vue-vben-admin/commit/28f7f7bf7f3ae49759b44395f6b06c2c61359d04))
- **lazy-container:** optimize lazyContainer code ([0f4b847](https://github.com/anncwb/vue-vben-admin/commit/0f4b847d69e90e5bbb4fb0883fb5ea1dd1daf1e7))
- **logo:** optimize logo code ([e79e540](https://github.com/anncwb/vue-vben-admin/commit/e79e540b48be80fb08b67a99e64bede3816b2c9e))
- **menu:** optimize layout menu ([96c10d6](https://github.com/anncwb/vue-vben-admin/commit/96c10d6c0fb46b56b0e74e09a8e20bcfc9f54cde))
- **modal:** optimize table embedding height calculation problem ([9abf176](https://github.com/anncwb/vue-vben-admin/commit/9abf1763c78ead7de21ece6d328337a6a1da5f05))
- **strength-meter:** modify name word ([#38](https://github.com/anncwb/vue-vben-admin/issues/38)) ([19477cd](https://github.com/anncwb/vue-vben-admin/commit/19477cd980661ace337ec6e3295f76c44d05763c))
- **table:** optimize effect performance ([a1ffb61](https://github.com/anncwb/vue-vben-admin/commit/a1ffb61804940f1ebaea741b0df41485ad95d5f2))
- **upload:** improve upload component ([661db0c](https://github.com/anncwb/vue-vben-admin/commit/661db0c767772bb7a30da9d3eeaf2b47858ccf0b))
- **use-message:** fix typo ([bcab4b7](https://github.com/anncwb/vue-vben-admin/commit/bcab4b774d384a5de9b87a0c700a9937c79eb5cd))
- perf TableAction ([4b384b1](https://github.com/anncwb/vue-vben-admin/commit/4b384b137c58428f0cf28621e183250da4576479))
- performance optimization ([70fba7e](https://github.com/anncwb/vue-vben-admin/commit/70fba7ecac80a1cd8ec08052e8265641f2b56204))
- pwa icon ([404c73d](https://github.com/anncwb/vue-vben-admin/commit/404c73de450c165ffe623ca2969322bae1786a73))
- remove optional chain ([e034d1b](https://github.com/anncwb/vue-vben-admin/commit/e034d1bacc5501a83188d20129951422bc127e3b))
- review tinymce code ([f75425d](https://github.com/anncwb/vue-vben-admin/commit/f75425d13bc9f6003021fd4b5d6451ae096c09b7))
- set cache default time ([c620f82](https://github.com/anncwb/vue-vben-admin/commit/c620f8279f1056ddab84b3907fb50b3af4fe9247))
- tabs optimization ([6e40051](https://github.com/anncwb/vue-vben-admin/commit/6e4005111db58ca10f10e9aa4bca4aec57363736))
- the existing tab switching no longer displays animation and processbar ([e9536b5](https://github.com/anncwb/vue-vben-admin/commit/e9536b5b7ccc5f667496c4ec7ab838738f804a71))
- the routeModule can ignore the layou configuration without writing ([4c658f4](https://github.com/anncwb/vue-vben-admin/commit/4c658f4868c7df6e0b8f18728c5d5ae53b04448a))
- update form types ([a0c3197](https://github.com/anncwb/vue-vben-admin/commit/a0c3197454b59a231cf6d27048b2e9c0bd7bf77f))
### Reverts
- **table:** revert form type annotation ([261936b](https://github.com/anncwb/vue-vben-admin/commit/261936b117d1d261ecb8fafc0f6c839cb2913918))
# [2.0.0-beta.3](https://github.com/anncwb/vue-vben-admin/compare/2.0.0-beta.2...2.0.0-beta.3) (2020-10-07)
### Features
- **setting:** add openNProgress setting ([67d0ff0](https://github.com/anncwb/vue-vben-admin/commit/67d0ff0e251f584883d50fd71b2413b6ca94729d))
- **table:** add table component ([faf3f46](https://github.com/anncwb/vue-vben-admin/commit/faf3f4602ecf4b16ff57994668edc8433a43945d))
# [2.0.0-beta.2](https://github.com/anncwb/vue-vben-admin/compare/2.0.0-beta.1...2.0.0-beta.2) (2020-10-07)
### Features
- **img-preview:** add imgPreview componnt ([e6093aa](https://github.com/anncwb/vue-vben-admin/commit/e6093aa4f48f3b3c16b1640c56512e6e3cf84c4b))
# [2.0.0-beta.1](https://github.com/anncwb/vue-vben-admin/compare/2f268ca8f43d98687ffd809e2c1d140d29033bd6...2.0.0-beta.1) (2020-09-30)
### Bug Fixes
- fix form,transition,build bug ([2f268ca](https://github.com/anncwb/vue-vben-admin/commit/2f268ca8f43d98687ffd809e2c1d140d29033bd6))

View File

@@ -1,3 +1,58 @@
## 2.0.1 (2021-03-04)
### ✨ Refactor
- 重构多语言模块,支持懒加载及远程加载
### ✨ Features
- axios 支持 form-data 格式请求
- 新增图标选择器组件(支持本地和在线方式)
- 新增 WebSocket 示例和服务脚本
- Tree 组件新增 `renderIcon` 属性用于控制层级图标显示
- Tree->actionItem 新增 show 属性,用于动态控制按钮显示
- Tree 新增工具栏/title/搜索功能
- 新增部门管理/修改密码/账号管理/角色管理/菜单管理示例界面
### ⚡ Performance Improvements
- 登录界面动画优化
- 修复 github 仓库体积过大问题.
- 默认隐藏表格全屏按钮
- `crypto-es`改为`crypto-js`,减小打包体积
- `types`目录移动到根目录,兼容其他目录全局类型
### 🐛 Bug Fixes
- 修复验证码组件警告问题
- 修复表格不能正确的获取选中行
- 修复全屏状态下 modal 高度计算错误
- 修复部分表格样式问题
- 修复树形表格 `indentSize`设置失效
## 2.0.1 (2021-02-21)
### ✨ Refactor
- 登录页重构,新增注册页面/重置密码页面/手机登录/二维码登录
### ✨ Features
- 新增 `settingButtonPosition`配置项,用于配置`设置`按钮位置
- `modal`可以通过双击头部切换全屏
- 新增`CountDownInput`组件
### ⚡ Performance Improvements
- 优化可编辑居中样式及下拉框宽度过短
- 表格新增编辑时`edit-change`事件监听
### 🐛 Bug Fixes
- 修复图片预览样式错误
- 修复图标样式问题
- 修复可编辑表格下拉回显问题
## 2.0.0 (2021-02-18) ## 2.0.0 (2021-02-18)
## (破坏性更新) Breaking changes ## (破坏性更新) Breaking changes

View File

@@ -94,7 +94,7 @@ export function generateModifyVars() {
'disabled-color': 'rgba(0, 0, 0, 0.25)', // Failure color 'disabled-color': 'rgba(0, 0, 0, 0.25)', // Failure color
'heading-color': 'rgba(0, 0, 0, 0.85)', // Title color 'heading-color': 'rgba(0, 0, 0, 0.85)', // Title color
'text-color': 'rgba(0, 0, 0, 0.85)', // Main text color 'text-color': 'rgba(0, 0, 0, 0.85)', // Main text color
'text-color-secondary ': 'rgba(0, 0, 0, 0.45)', // Subtext color 'text-color-secondary': 'rgba(0, 0, 0, 0.45)', // Subtext color
'font-size-base': '14px', // Main font size 'font-size-base': '14px', // Main font size
'box-shadow-base': '0 2px 8px rgba(0, 0, 0, 0.15)', // Floating shadow 'box-shadow-base': '0 2px 8px rgba(0, 0, 0, 0.15)', // Floating shadow
'border-color-base': '#d9d9d9', // Border color, 'border-color-base': '#d9d9d9', // Border color,

View File

@@ -0,0 +1,72 @@
import path from 'path';
import fs from 'fs-extra';
import inquirer from 'inquirer';
import chalk from 'chalk';
import pkg from '../../package.json';
async function generateIcon() {
const dir = path.resolve(process.cwd(), 'node_modules/@iconify/json');
const raw = await fs.readJSON(path.join(dir, 'collections.json'));
const collections = Object.entries(raw).map(([id, v]) => ({
...(v as any),
id,
}));
const choices = collections.map((item) => ({ key: item.id, value: item.id, name: item.name }));
inquirer
.prompt([
{
type: 'list',
name: 'useType',
choices: [
{ key: 'local', value: 'local', name: 'Local' },
{ key: 'onLine', value: 'onLine', name: 'OnLine' },
],
message: 'How to use icons?',
},
{
type: 'list',
name: 'iconSet',
choices: choices,
message: 'Select the icon set that needs to be generated?',
},
{
type: 'input',
name: 'output',
message: 'Select the icon set that needs to be generated?',
default: 'src/components/Icon/data',
},
])
.then(async (answers) => {
const { iconSet, output, useType } = answers;
const outputDir = path.resolve(process.cwd(), output);
fs.ensureDir(outputDir);
const genCollections = collections.filter((item) => [iconSet].includes(item.id));
const prefixSet: string[] = [];
for (const info of genCollections) {
const data = await fs.readJSON(path.join(dir, 'json', `${info.id}.json`));
if (data) {
const { prefix } = data;
const isLocal = useType === 'local';
const icons = Object.keys(data.icons).map(
(item) => `${isLocal ? prefix + ':' : ''}${item}`
);
await fs.writeFileSync(
path.join(output, `icons.data.ts`),
`export default ${isLocal ? JSON.stringify(icons) : JSON.stringify({ prefix, icons })}`
);
prefixSet.push(prefix);
}
}
fs.emptyDir(path.join(process.cwd(), 'node_modules/.vite'));
console.log(
`${chalk.cyan(`[${pkg.name}]`)}` + ' - Icon generated successfully:' + `[${prefixSet}]`
);
});
}
generateIcon();

View File

@@ -2,7 +2,7 @@
* Get the configuration file variable name * Get the configuration file variable name
* @param env * @param env
*/ */
export const getShortName = (env: any) => { export const getConfigFileName = (env: Record<string, any>) => {
return `__PRODUCTION__${env.VITE_GLOB_APP_SHORT_NAME || '__APP'}__CONF__` return `__PRODUCTION__${env.VITE_GLOB_APP_SHORT_NAME || '__APP'}__CONF__`
.toUpperCase() .toUpperCase()
.replace(/\s/g, ''); .replace(/\s/g, '');

View File

@@ -5,8 +5,8 @@ import { GLOB_CONFIG_FILE_NAME, OUTPUT_DIR } from '../constant';
import fs, { writeFileSync } from 'fs-extra'; import fs, { writeFileSync } from 'fs-extra';
import chalk from 'chalk'; import chalk from 'chalk';
import { getCwdPath, getEnvConfig } from '../utils'; import { getRootPath, getEnvConfig } from '../utils';
import { getShortName } from '../getShortName'; import { getConfigFileName } from '../getConfigFileName';
import pkg from '../../package.json'; import pkg from '../../package.json';
@@ -27,8 +27,8 @@ function createConfig(
writable: false, writable: false,
}); });
`.replace(/\s/g, ''); `.replace(/\s/g, '');
fs.mkdirp(getCwdPath(OUTPUT_DIR)); fs.mkdirp(getRootPath(OUTPUT_DIR));
writeFileSync(getCwdPath(`${OUTPUT_DIR}/${configFileName}`), configStr); writeFileSync(getRootPath(`${OUTPUT_DIR}/${configFileName}`), configStr);
console.log(chalk.cyan(`✨ [${pkg.name}]`) + ` - configuration file is build successfully:`); console.log(chalk.cyan(`✨ [${pkg.name}]`) + ` - configuration file is build successfully:`);
console.log(chalk.gray(OUTPUT_DIR + '/' + chalk.green(configFileName)) + '\n'); console.log(chalk.gray(OUTPUT_DIR + '/' + chalk.green(configFileName)) + '\n');
@@ -39,6 +39,6 @@ function createConfig(
export function runBuildConfig() { export function runBuildConfig() {
const config = getEnvConfig(); const config = getEnvConfig();
const configFileName = getShortName(config); const configFileName = getConfigFileName(config);
createConfig({ config, configName: configFileName }); createConfig({ config, configName: configFileName });
} }

View File

@@ -14,6 +14,7 @@ export const runBuild = async () => {
if (!argvList.includes('no-conf')) { if (!argvList.includes('no-conf')) {
await runBuildConfig(); await runBuildConfig();
} }
console.log(`${chalk.cyan(`[${pkg.name}]`)}` + ' - build successfully!'); console.log(`${chalk.cyan(`[${pkg.name}]`)}` + ' - build successfully!');
} catch (error) { } catch (error) {
console.log(chalk.red('vite build error:\n' + error)); console.log(chalk.red('vite build error:\n' + error));

View File

@@ -5,7 +5,6 @@
"moduleResolution": "node", "moduleResolution": "node",
"strict": true, "strict": true,
"forceConsistentCasingInFileNames": true, "forceConsistentCasingInFileNames": true,
"jsx": "react",
"baseUrl": ".", "baseUrl": ".",
"esModuleInterop": true, "esModuleInterop": true,
"noUnusedLocals": true, "noUnusedLocals": true,

2
build/typeing.d.ts vendored
View File

@@ -2,3 +2,5 @@ declare module '*.json' {
const src: any; const src: any;
export default src; export default src;
} }
declare type Recordable = Record<string, any>;

View File

@@ -2,12 +2,6 @@ import fs from 'fs';
import path from 'path'; import path from 'path';
import dotenv from 'dotenv'; import dotenv from 'dotenv';
export const isFunction = (arg: unknown): arg is (...args: any[]) => any =>
typeof arg === 'function';
export const isRegExp = (arg: unknown): arg is RegExp =>
Object.prototype.toString.call(arg) === '[object RegExp]';
export function isDevFn(mode: string): boolean { export function isDevFn(mode: string): boolean {
return mode === 'development'; return mode === 'development';
} }
@@ -34,18 +28,18 @@ export interface ViteEnv {
VITE_USE_CDN: boolean; VITE_USE_CDN: boolean;
VITE_DROP_CONSOLE: boolean; VITE_DROP_CONSOLE: boolean;
VITE_BUILD_COMPRESS: 'gzip' | 'brotli' | 'none'; VITE_BUILD_COMPRESS: 'gzip' | 'brotli' | 'none';
VITE_DYNAMIC_IMPORT: boolean;
VITE_LEGACY: boolean; VITE_LEGACY: boolean;
VITE_USE_IMAGEMIN: boolean; VITE_USE_IMAGEMIN: boolean;
} }
// Read all environment variable configuration files to process.env // Read all environment variable configuration files to process.env
export function wrapperEnv(envConf: any): ViteEnv { export function wrapperEnv(envConf: Recordable): ViteEnv {
const ret: any = {}; const ret: any = {};
for (const envName of Object.keys(envConf)) { for (const envName of Object.keys(envConf)) {
let realName = envConf[envName].replace(/\\n/g, '\n'); let realName = envConf[envName].replace(/\\n/g, '\n');
realName = realName === 'true' ? true : realName === 'false' ? false : realName; realName = realName === 'true' ? true : realName === 'false' ? false : realName;
if (envName === 'VITE_PORT') { if (envName === 'VITE_PORT') {
realName = Number(realName); realName = Number(realName);
} }
@@ -70,10 +64,10 @@ export function getEnvConfig(match = 'VITE_GLOB_', confFiles = ['.env', '.env.pr
confFiles.forEach((item) => { confFiles.forEach((item) => {
try { try {
const env = dotenv.parse(fs.readFileSync(path.resolve(process.cwd(), item))); const env = dotenv.parse(fs.readFileSync(path.resolve(process.cwd(), item)));
envConfig = { ...envConfig, ...env }; envConfig = { ...envConfig, ...env };
} catch (error) {} } catch (error) {}
}); });
Object.keys(envConfig).forEach((key) => { Object.keys(envConfig).forEach((key) => {
const reg = new RegExp(`^(${match})`); const reg = new RegExp(`^(${match})`);
if (!reg.test(key)) { if (!reg.test(key)) {
@@ -87,6 +81,6 @@ export function getEnvConfig(match = 'VITE_GLOB_', confFiles = ['.env', '.env.pr
* Get user root directory * Get user root directory
* @param dir file path * @param dir file path
*/ */
export function getCwdPath(...dir: string[]) { export function getRootPath(...dir: string[]) {
return path.resolve(process.cwd(), ...dir); return path.resolve(process.cwd(), ...dir);
} }

View File

@@ -1,5 +1,6 @@
/** /**
* Used to package and output gzip. Note that this does not work properly in Vite, the specific reason is still being investigated * Used to package and output gzip. Note that this does not work properly in Vite, the specific reason is still being investigated
* https://github.com/anncwb/vite-plugin-compression
*/ */
import type { Plugin } from 'vite'; import type { Plugin } from 'vite';

View File

@@ -1,4 +1,5 @@
// Image resource files used to compress the output of the production environment // Image resource files used to compress the output of the production environment
// https://github.com/anncwb/vite-plugin-imagemin
import viteImagemin from 'vite-plugin-imagemin'; import viteImagemin from 'vite-plugin-imagemin';
@@ -15,10 +16,10 @@ export function configImageminPlugin() {
quality: 75, quality: 75,
}, },
mozjpeg: { mozjpeg: {
quality: 65, quality: 8,
}, },
pngquant: { pngquant: {
quality: [0.65, 0.9], quality: [0.8, 0.9],
speed: 4, speed: 4,
}, },
svgo: { svgo: {

View File

@@ -1,13 +1,12 @@
import type { Plugin } from 'vite'; import type { Plugin } from 'vite';
import type { ViteEnv } from '../../utils';
import vue from '@vitejs/plugin-vue'; import vue from '@vitejs/plugin-vue';
import vueJsx from '@vitejs/plugin-vue-jsx'; import vueJsx from '@vitejs/plugin-vue-jsx';
import legacy from '@vitejs/plugin-legacy'; import legacy from '@vitejs/plugin-legacy';
import windiCSS from 'vite-plugin-windicss';
import PurgeIcons from 'vite-plugin-purge-icons'; import PurgeIcons from 'vite-plugin-purge-icons';
import { ViteEnv } from '../../utils';
import { configHtmlPlugin } from './html'; import { configHtmlPlugin } from './html';
import { configPwaConfig } from './pwa'; import { configPwaConfig } from './pwa';
import { configMockPlugin } from './mock'; import { configMockPlugin } from './mock';
@@ -16,6 +15,7 @@ import { configStyleImportPlugin } from './styleImport';
import { configVisualizerConfig } from './visualizer'; import { configVisualizerConfig } from './visualizer';
import { configThemePlugin } from './theme'; import { configThemePlugin } from './theme';
import { configImageminPlugin } from './imagemin'; import { configImageminPlugin } from './imagemin';
import { configWindiCssPlugin } from './windicss';
export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean) { export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean) {
const { VITE_USE_IMAGEMIN, VITE_USE_MOCK, VITE_LEGACY, VITE_BUILD_COMPRESS } = viteEnv; const { VITE_USE_IMAGEMIN, VITE_USE_MOCK, VITE_LEGACY, VITE_BUILD_COMPRESS } = viteEnv;
@@ -25,7 +25,6 @@ export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean) {
vue(), vue(),
// have to // have to
vueJsx(), vueJsx(),
...windiCSS(),
]; ];
// @vitejs/plugin-legacy // @vitejs/plugin-legacy
@@ -34,6 +33,9 @@ export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean) {
// vite-plugin-html // vite-plugin-html
vitePlugins.push(configHtmlPlugin(viteEnv, isBuild)); vitePlugins.push(configHtmlPlugin(viteEnv, isBuild));
// vite-plugin-windicss
vitePlugins.push(configWindiCssPlugin());
// vite-plugin-mock // vite-plugin-mock
VITE_USE_MOCK && vitePlugins.push(configMockPlugin(isBuild)); VITE_USE_MOCK && vitePlugins.push(configMockPlugin(isBuild));

View File

@@ -2,11 +2,10 @@
* Zero-config PWA for Vite * Zero-config PWA for Vite
* https://github.com/antfu/vite-plugin-pwa * https://github.com/antfu/vite-plugin-pwa
*/ */
import type { ViteEnv } from '../../utils';
import { VitePWA } from 'vite-plugin-pwa'; import { VitePWA } from 'vite-plugin-pwa';
import { ViteEnv } from '../../utils';
export function configPwaConfig(env: ViteEnv) { export function configPwaConfig(env: ViteEnv) {
const { VITE_USE_PWA, VITE_GLOB_APP_TITLE, VITE_GLOB_APP_SHORT_NAME } = env; const { VITE_USE_PWA, VITE_GLOB_APP_TITLE, VITE_GLOB_APP_SHORT_NAME } = env;

View File

@@ -9,6 +9,10 @@ export function configVisualizerConfig() {
return visualizer({ return visualizer({
filename: './node_modules/.cache/visualizer/stats.html', filename: './node_modules/.cache/visualizer/stats.html',
open: true, open: true,
// @ts-ignore
gzipSize: true,
// @ts-ignore
brotliSize: true,
}) as Plugin; }) as Plugin;
} }
return []; return [];

View File

@@ -0,0 +1,12 @@
import type { Plugin } from 'vite';
import windiCSS from 'vite-plugin-windicss';
export function configWindiCssPlugin(): Plugin[] {
return windiCSS({
safelist: 'no-select',
preflight: {
enableAll: true,
},
});
}

View File

@@ -1,5 +1,6 @@
import { createProdMockServer } from 'vite-plugin-mock/es/createProdMockServer'; import { createProdMockServer } from 'vite-plugin-mock/es/createProdMockServer';
// @ts-ignore
const modules = import.meta.globEager('./**/*.ts'); const modules = import.meta.globEager('./**/*.ts');
const mockModules: any[] = []; const mockModules: any[] = [];

View File

@@ -18,13 +18,11 @@ export function resultPageSuccess<T = any>(
const pageData = pagination(page, pageSize, list); const pageData = pagination(page, pageSize, list);
return { return {
code: 0, ...resultSuccess({
result: {
items: pageData, items: pageData,
total: list.length, total: list.length,
}, }),
message, message,
type: 'success',
}; };
} }

151
mock/demo/system.ts Normal file
View File

@@ -0,0 +1,151 @@
import { MockMethod } from 'vite-plugin-mock';
import { resultPageSuccess, resultSuccess } from '../_util';
const accountList = (() => {
const result: any[] = [];
for (let index = 0; index < 20; index++) {
result.push({
id: `${index}`,
account: '@first',
email: '@email',
nickname: '@cname()',
role: '@first',
createTime: '@datetime',
remark: '@cword(10,20)',
'status|1': ['0', '1'],
});
}
return result;
})();
const roleList = (() => {
const result: any[] = [];
for (let index = 0; index < 4; index++) {
result.push({
id: `${index}`,
orderNo: `${index + 1}`,
roleName: ['超级管理员', '管理员', '文章管理员', '普通用户'][index],
roleValue: '@first',
createTime: '@datetime',
remark: '@cword(10,20)',
'status|1': ['0', '1'],
});
}
return result;
})();
const deptList = (() => {
const result: any[] = [];
for (let index = 0; index < 3; index++) {
result.push({
id: `${index}`,
deptName: ['华东分部', '华南分部', '西北分部'][index],
orderNo: index + 1,
createTime: '@datetime',
remark: '@cword(10,20)',
'status|1': ['0', '0', '1'],
children: (() => {
const children: any[] = [];
for (let j = 0; j < 4; j++) {
children.push({
id: `${index}-${j}`,
deptName: ['研发部', '市场部', '商务部', '财务部'][j],
orderNo: j + 1,
createTime: '@datetime',
remark: '@cword(10,20)',
'status|1': ['0', '1'],
parentDept: `${index}`,
children: undefined,
});
}
return children;
})(),
});
}
return result;
})();
const menuList = (() => {
const result: any[] = [];
for (let index = 0; index < 3; index++) {
result.push({
id: `${index}`,
icon: ['ion:layers-outline', 'ion:git-compare-outline', 'ion:tv-outline'][index],
component: 'LAYOUT',
menuName: ['Dashboard', '权限管理', '功能'][index],
permission: '',
orderNo: index + 1,
createTime: '@datetime',
'status|1': ['0', '0', '1'],
children: (() => {
const children: any[] = [];
for (let j = 0; j < 4; j++) {
children.push({
id: `${index}-${j}`,
menuName: ['菜单1', '菜单2', '菜单3', '菜单4'][j],
icon: 'ion:document',
permission: ['menu1:view', 'menu2:add', 'menu3:update', 'menu4:del'][index],
component: [
'/dashboard/welcome/index',
'/dashboard/analysis/index',
'/dashboard/workbench/index',
'/dashboard/test/index',
][j],
orderNo: j + 1,
createTime: '@datetime',
'status|1': ['0', '1'],
parentMenu: `${index}`,
children: undefined,
});
}
return children;
})(),
});
}
return result;
})();
export default [
{
url: '/api/system/getAccountList',
timeout: 100,
method: 'get',
response: ({ query }) => {
const { page = 1, pageSize = 20 } = query;
return resultPageSuccess(page, pageSize, accountList);
},
},
{
url: '/api/system/getRoleListByPage',
timeout: 100,
method: 'get',
response: ({ query }) => {
const { page = 1, pageSize = 20 } = query;
return resultPageSuccess(page, pageSize, roleList);
},
},
{
url: '/api/system/getAllRoleList',
timeout: 100,
method: 'get',
response: () => {
return resultSuccess(roleList);
},
},
{
url: '/api/system/getDeptList',
timeout: 100,
method: 'get',
response: () => {
return resultSuccess(deptList);
},
},
{
url: '/api/system/getMenuList',
timeout: 100,
method: 'get',
response: () => {
return resultSuccess(menuList);
},
},
] as MockMethod[];

View File

@@ -28,7 +28,7 @@ const demoList = (() => {
export default [ export default [
{ {
url: '/api/table/getDemoList', url: '/api/table/getDemoList',
timeout: 1000, timeout: 100,
method: 'get', method: 'get',
response: ({ query }) => { response: ({ query }) => {
const { page = 1, pageSize = 20 } = query; const { page = 1, pageSize = 20 } = query;

View File

@@ -1,6 +1,6 @@
{ {
"name": "vben-admin", "name": "vben-admin",
"version": "2.0.0", "version": "2.0.2",
"scripts": { "scripts": {
"bootstrap": "yarn install", "bootstrap": "yarn install",
"serve": "vite", "serve": "vite",
@@ -10,111 +10,113 @@
"report": "cross-env REPORT=true npm run build ", "report": "cross-env REPORT=true npm run build ",
"preview": "npm run build && vite preview", "preview": "npm run build && vite preview",
"preview:dist": "vite preview", "preview:dist": "vite preview",
"log": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0", "log": "conventional-changelog -p angular -i CHANGELOG.md -s",
"clean:cache": "rimraf node_modules/.cache/ && rimraf node_modules/.vite", "clean:cache": "rimraf node_modules/.cache/ && rimraf node_modules/.vite",
"clean:lib": "npx rimraf node_modules", "clean:lib": "rimraf node_modules",
"typecheck": "vuedx-typecheck .",
"lint:eslint": "eslint \"{src,mock}/**/*.{vue,ts,tsx}\" --fix", "lint:eslint": "eslint \"{src,mock}/**/*.{vue,ts,tsx}\" --fix",
"lint:prettier": "prettier --write --loglevel warn \"src/**/*.{js,json,tsx,css,less,scss,vue,html,md}\"", "lint:prettier": "prettier --write --loglevel warn \"src/**/*.{js,json,tsx,css,less,scss,vue,html,md}\"",
"lint:stylelint": "stylelint --fix \"**/*.{vue,less,postcss,css,scss}\" --cache --cache-location node_modules/.cache/stylelint/", "lint:stylelint": "stylelint --fix \"**/*.{vue,less,postcss,css,scss}\" --cache --cache-location node_modules/.cache/stylelint/",
"lint:ls-lint": "ls-lint", "lint:ls-lint": "ls-lint",
"lint:lint-staged": "lint-staged -c ./.husky/lintstagedrc.js", "lint:lint-staged": "lint-staged -c ./.husky/lintstagedrc.js",
"lint:pretty": "pretty-quick --staged",
"test:gzip": "http-server dist --cors --gzip -c-1", "test:gzip": "http-server dist --cors --gzip -c-1",
"test:br": "http-server dist --cors --brotli -c-1", "test:br": "http-server dist --cors --brotli -c-1",
"reinstall": "rimraf yarn.lock && rimraf package.lock.json && rimraf node_modules && npm run bootstrap", "reinstall": "rimraf yarn.lock && rimraf package.lock.json && rimraf node_modules && npm run bootstrap",
"postinstall": "is-ci || husky install" "install:husky": "is-ci || husky install",
"gen:icon": "esno ./build/gen/generateIconJson.ts",
"postinstall": "npm run install:husky"
}, },
"dependencies": { "dependencies": {
"@iconify/iconify": "^2.0.0-rc.6", "@iconify/iconify": "^2.0.0-rc.6",
"@vueuse/core": "^4.1.1", "@vueuse/core": "^4.3.1",
"ant-design-vue": "2.0.0", "@zxcvbn-ts/core": "^0.3.0",
"ant-design-vue": "2.0.1",
"apexcharts": "^3.25.0", "apexcharts": "^3.25.0",
"axios": "^0.21.1", "axios": "^0.21.1",
"crypto-es": "^1.2.7", "crypto-js": "^4.0.0",
"echarts": "^5.0.2", "echarts": "^5.0.2",
"lodash-es": "^4.17.20", "lodash-es": "^4.17.21",
"mockjs": "^1.1.0", "mockjs": "^1.1.0",
"nprogress": "^0.2.0", "nprogress": "^0.2.0",
"path-to-regexp": "^6.2.0", "path-to-regexp": "^6.2.0",
"qrcode": "^1.4.4", "qrcode": "^1.4.4",
"sortablejs": "^1.13.0", "sortablejs": "^1.13.0",
"vditor": "^3.8.1", "vditor": "^3.8.2",
"vue": "^3.0.5", "vue": "^3.0.7",
"vue-i18n": "9.0.0-rc.2", "vue-i18n": "^9.0.0",
"vue-router": "^4.0.3", "vue-router": "^4.0.4",
"vue-types": "^3.0.2", "vue-types": "^3.0.2",
"vuex": "^4.0.0", "vuex": "^4.0.0",
"vuex-module-decorators": "^1.0.1", "vuex-module-decorators": "^1.0.1",
"xlsx": "^0.16.9", "xlsx": "^0.16.9"
"zxcvbn": "^4.4.2"
}, },
"devDependencies": { "devDependencies": {
"@commitlint/cli": "^11.0.0", "@commitlint/cli": "^12.0.1",
"@commitlint/config-conventional": "^11.0.0", "@commitlint/config-conventional": "^12.0.1",
"@iconify/json": "^1.1.303", "@iconify/json": "^1.1.311",
"@ls-lint/ls-lint": "^1.9.2", "@ls-lint/ls-lint": "^1.9.2",
"@purge-icons/generated": "^0.7.0", "@purge-icons/generated": "^0.7.0",
"@types/fs-extra": "^9.0.7", "@types/crypto-js": "^4.0.1",
"@types/fs-extra": "^9.0.8",
"@types/http-proxy": "^1.17.5", "@types/http-proxy": "^1.17.5",
"@types/koa-static": "^4.0.1", "@types/inquirer": "^7.3.1",
"@types/lodash-es": "^4.17.4", "@types/lodash-es": "^4.17.4",
"@types/mockjs": "^1.0.3", "@types/mockjs": "^1.0.3",
"@types/nprogress": "^0.2.0", "@types/nprogress": "^0.2.0",
"@types/qrcode": "^1.4.0", "@types/qrcode": "^1.4.0",
"@types/qs": "^6.9.5",
"@types/rollup-plugin-visualizer": "^2.6.0", "@types/rollup-plugin-visualizer": "^2.6.0",
"@types/sortablejs": "^1.10.6", "@types/sortablejs": "^1.10.6",
"@types/yargs": "^16.0.0", "@types/yargs": "^16.0.0",
"@types/zxcvbn": "^4.4.0", "@typescript-eslint/eslint-plugin": "^4.16.1",
"@typescript-eslint/eslint-plugin": "^4.15.1", "@typescript-eslint/parser": "^4.16.1",
"@typescript-eslint/parser": "^4.15.1",
"@vitejs/plugin-legacy": "^1.3.1", "@vitejs/plugin-legacy": "^1.3.1",
"@vitejs/plugin-vue": "^1.1.4", "@vitejs/plugin-vue": "^1.1.5",
"@vitejs/plugin-vue-jsx": "^1.1.0", "@vitejs/plugin-vue-jsx": "^1.1.2",
"@vue/compiler-sfc": "^3.0.5", "@vue/compiler-sfc": "^3.0.7",
"@vuedx/typecheck": "^0.6.3",
"@vuedx/typescript-plugin-vue": "^0.6.3",
"autoprefixer": "^10.2.4", "autoprefixer": "^10.2.4",
"commitizen": "^4.2.3", "commitizen": "^4.2.3",
"conventional-changelog-cli": "^2.1.1", "conventional-changelog-cli": "^2.1.1",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"dotenv": "^8.2.0", "dotenv": "^8.2.0",
"eslint": "^7.20.0", "eslint": "^7.21.0",
"eslint-config-prettier": "^7.2.0", "eslint-config-prettier": "^8.1.0",
"eslint-plugin-prettier": "^3.3.1", "eslint-plugin-prettier": "^3.3.1",
"eslint-plugin-vue": "^7.6.0", "eslint-plugin-vue": "^7.7.0",
"esno": "^0.4.3", "esno": "^0.4.5",
"fs-extra": "^9.1.0", "fs-extra": "^9.1.0",
"http-server": "^0.12.3", "http-server": "^0.12.3",
"husky": "^5.0.9", "husky": "^5.1.3",
"is-ci": "^2.0.0", "inquirer": "^8.0.0",
"is-ci": "^3.0.0",
"less": "^4.1.1", "less": "^4.1.1",
"lint-staged": "^10.5.4", "lint-staged": "^10.5.4",
"prettier": "^2.2.1", "prettier": "^2.2.1",
"pretty-quick": "^3.1.0",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"rollup-plugin-visualizer": "^4.2.0", "rollup-plugin-visualizer": "^4.2.0",
"stylelint": "^13.10.0", "stylelint": "^13.11.0",
"stylelint-config-prettier": "^8.0.2", "stylelint-config-prettier": "^8.0.2",
"stylelint-config-standard": "^20.0.0", "stylelint-config-standard": "^20.0.0",
"stylelint-order": "^4.1.0", "stylelint-order": "^4.1.0",
"ts-node": "^9.1.1", "ts-node": "^9.1.1",
"typescript": "^4.1.5", "typescript": "4.2.2",
"vite": "2.0.0", "vite": "^2.0.5",
"vite-plugin-compression": "^0.2.1", "vite-plugin-compression": "^0.2.3",
"vite-plugin-html": "^2.0.0", "vite-plugin-html": "^2.0.3",
"vite-plugin-imagemin": "^0.2.6", "vite-plugin-imagemin": "^0.2.9",
"vite-plugin-mock": "^2.1.4", "vite-plugin-mock": "^2.2.0",
"vite-plugin-purge-icons": "^0.7.0", "vite-plugin-purge-icons": "^0.7.0",
"vite-plugin-pwa": "^0.4.7", "vite-plugin-pwa": "^0.5.6",
"vite-plugin-style-import": "^0.7.2", "vite-plugin-style-import": "^0.7.6",
"vite-plugin-theme": "^0.4.3", "vite-plugin-theme": "^0.4.8",
"vite-plugin-windicss": "^0.2.2", "vite-plugin-windicss": "0.6.4",
"vue-eslint-parser": "^7.5.0", "vue-eslint-parser": "^7.6.0",
"yargs": "^16.2.0" "yargs": "^16.2.0"
}, },
"resolutions": { "resolutions": {
"//": "Used to install imagemin dependencies, because imagemin may not be installed in China.If it is abroad, you can delete it", "//": "Used to install imagemin dependencies, because imagemin may not be installed in China.If it is abroad, you can delete it",
"bin-wrapper": "npm:bin-wrapper-china", "bin-wrapper": "npm:bin-wrapper-china"
"ecstatic": "4.1.4"
}, },
"repository": { "repository": {
"type": "git", "type": "git",

View File

@@ -1,5 +1,5 @@
<template> <template>
<ConfigProvider v-bind="lockEvent" :locale="antConfigLocale"> <ConfigProvider v-bind="lockEvent" :locale="getAntdLocale">
<AppProvider> <AppProvider>
<RouterView /> <RouterView />
</AppProvider> </AppProvider>
@@ -21,18 +21,15 @@
components: { ConfigProvider, AppProvider }, components: { ConfigProvider, AppProvider },
setup() { setup() {
// support Multi-language // support Multi-language
const { antConfigLocale, setLocale } = useLocale(); const { getAntdLocale } = useLocale();
setLocale();
// Initialize vuex internal system configuration // Initialize vuex internal system configuration
initAppConfigStore(); initAppConfigStore();
// Create a lock screen monitor // Create a lock screen monitor
const lockEvent = useLockPage(); const lockEvent = useLockPage();
return { return { getAntdLocale, lockEvent };
antConfigLocale,
lockEvent,
};
}, },
}); });
</script> </script>

View File

@@ -6,9 +6,5 @@ enum Api {
} }
// Get personal center-basic settings // Get personal center-basic settings
export function accountInfoApi() {
return defHttp.request<GetAccountInfoModel>({ export const accountInfoApi = () => defHttp.get<GetAccountInfoModel>({ url: Api.ACCOUNT_INFO });
url: Api.ACCOUNT_INFO,
method: 'GET',
});
}

View File

@@ -8,9 +8,5 @@ enum Api {
/** /**
* @description: Trigger ajax error * @description: Trigger ajax error
*/ */
export function fireErrorApi() {
return defHttp.request({ export const fireErrorApi = () => defHttp.get({ url: Api.Error });
url: Api.Error,
method: 'GET',
});
}

View File

@@ -0,0 +1,74 @@
import { BasicPageParams, BasicFetchResult } from '/@/api/model/baseModel';
export type AccountParams = BasicPageParams & {
account?: string;
nickname?: string;
};
export type RoleParams = {
roleName?: string;
status?: string;
};
export type RolePageParams = BasicPageParams & RoleParams;
export type DeptParams = {
deptName?: string;
status?: string;
};
export type MenuParams = {
menuName?: string;
status?: string;
};
export interface AccountListItem {
id: string;
account: string;
email: string;
nickname: string;
role: number;
createTime: string;
remark: string;
status: number;
}
export interface DeptListItem {
id: string;
orderNo: string;
createTime: string;
remark: string;
status: number;
}
export interface MenuListItem {
id: string;
orderNo: string;
createTime: string;
status: number;
icon: string;
component: string;
permission: string;
}
export interface RoleListItem {
id: string;
roleName: string;
roleValue: string;
status: number;
orderNo: string;
createTime: string;
}
/**
* @description: Request list return value
*/
export type AccountListGetResultModel = BasicFetchResult<AccountListItem>;
export type DeptListGetResultModel = BasicFetchResult<DeptListItem>;
export type MenuListGetResultModel = BasicFetchResult<MenuListItem>;
export type RolePageListGetResultModel = BasicFetchResult<RoleListItem>;
export type RoleListGetResultModel = RoleListItem[];

View File

@@ -8,9 +8,5 @@ enum Api {
/** /**
* @description: Get sample options value * @description: Get sample options value
*/ */
export function optionsListApi() { export const optionsListApi = () =>
return defHttp.request<DemoOptionsGetResultModel>({ defHttp.get<DemoOptionsGetResultModel>({ url: Api.OPTIONS_LIST });
url: Api.OPTIONS_LIST,
method: 'GET',
});
}

36
src/api/demo/system.ts Normal file
View File

@@ -0,0 +1,36 @@
import {
AccountParams,
DeptListItem,
MenuParams,
RoleParams,
RolePageParams,
MenuListGetResultModel,
DeptListGetResultModel,
AccountListGetResultModel,
RolePageListGetResultModel,
RoleListGetResultModel,
} from './model/systemModel';
import { defHttp } from '/@/utils/http/axios';
enum Api {
AccountList = '/system/getAccountList',
DeptList = '/system/getDeptList',
MenuList = '/system/getMenuList',
RolePageList = '/system/getRoleListByPage',
GetAllRoleList = '/system/getAllRoleList',
}
export const getAccountList = (params: AccountParams) =>
defHttp.get<AccountListGetResultModel>({ url: Api.AccountList, params });
export const getDeptList = (params?: DeptListItem) =>
defHttp.get<DeptListGetResultModel>({ url: Api.DeptList, params });
export const getMenuList = (params?: MenuParams) =>
defHttp.get<MenuListGetResultModel>({ url: Api.MenuList, params });
export const getRoleListByPage = (params?: RolePageParams) =>
defHttp.get<RolePageListGetResultModel>({ url: Api.RolePageList, params });
export const getAllRoleList = (params?: RoleParams) =>
defHttp.get<RoleListGetResultModel>({ url: Api.GetAllRoleList, params });

View File

@@ -8,13 +8,12 @@ enum Api {
/** /**
* @description: Get sample list value * @description: Get sample list value
*/ */
export function demoListApi(params: DemoParams) {
return defHttp.request<DemoListGetResultModel>({ export const demoListApi = (params: DemoParams) =>
defHttp.get<DemoListGetResultModel>({
url: Api.DEMO_LIST, url: Api.DEMO_LIST,
method: 'GET',
params, params,
headers: { headers: {
ignoreCancelToken: true, ignoreCancelToken: true,
}, },
}); });
}

View File

@@ -1,5 +1,4 @@
import { defHttp } from '/@/utils/http/axios'; import { defHttp } from '/@/utils/http/axios';
import { getMenuListByIdParams, getMenuListByIdParamsResultModel } from './model/menuModel'; import { getMenuListByIdParams, getMenuListByIdParamsResultModel } from './model/menuModel';
enum Api { enum Api {
@@ -9,10 +8,7 @@ enum Api {
/** /**
* @description: Get user menu based on id * @description: Get user menu based on id
*/ */
export function getMenuListById(params: getMenuListByIdParams) {
return defHttp.request<getMenuListByIdParamsResultModel>({ export const getMenuListById = (params: getMenuListByIdParams) => {
url: Api.GetMenuListById, return defHttp.get<getMenuListByIdParamsResultModel>({ url: Api.GetMenuListById, params });
method: 'GET', };
params,
});
}

View File

@@ -17,10 +17,9 @@ enum Api {
* @description: user login api * @description: user login api
*/ */
export function loginApi(params: LoginParams, mode: ErrorMessageMode = 'modal') { export function loginApi(params: LoginParams, mode: ErrorMessageMode = 'modal') {
return defHttp.request<LoginResultModel>( return defHttp.post<LoginResultModel>(
{ {
url: Api.Login, url: Api.Login,
method: 'POST',
params, params,
}, },
{ {
@@ -33,17 +32,15 @@ export function loginApi(params: LoginParams, mode: ErrorMessageMode = 'modal')
* @description: getUserInfoById * @description: getUserInfoById
*/ */
export function getUserInfoById(params: GetUserInfoByUserIdParams) { export function getUserInfoById(params: GetUserInfoByUserIdParams) {
return defHttp.request<GetUserInfoByUserIdModel>({ return defHttp.get<GetUserInfoByUserIdModel>({
url: Api.GetUserInfoById, url: Api.GetUserInfoById,
method: 'GET',
params, params,
}); });
} }
export function getPermCodeByUserId(params: GetUserInfoByUserIdParams) { export function getPermCodeByUserId(params: GetUserInfoByUserIdParams) {
return defHttp.request<string[]>({ return defHttp.get<string[]>({
url: Api.GetPermCodeByUserId, url: Api.GetPermCodeByUserId,
method: 'GET',
params, params,
}); });
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 180 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

View File

@@ -0,0 +1,17 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="6395" height="1079" viewBox="0 0 6395 1079">
<defs>
<clipPath id="clip-path">
<rect id="Rectangle_73" data-name="Rectangle 73" width="6395" height="1079" transform="translate(-5391)" fill="#fff"/>
</clipPath>
<linearGradient id="linear-gradient" x1="0.747" y1="0.222" x2="0.973" y2="0.807" gradientUnits="objectBoundingBox">
<stop offset="0" stop-color="#2b51b4"/>
<stop offset="1" stop-color="#1c3faa"/>
</linearGradient>
</defs>
<g id="Mask_Group_1" data-name="Mask Group 1" transform="translate(5391)" clip-path="url(#clip-path)">
<g id="Group_118" data-name="Group 118" transform="translate(-419.333 -1.126)">
<path id="Path_142" data-name="Path 142" d="M6271.734-6.176s-222.478,187.809-55.349,583.254c44.957,106.375,81.514,205.964,84.521,277,8.164,192.764-156.046,268.564-156.046,268.564l-653.53-26.8L5475.065-21.625Z" transform="translate(-4876.383 0)" fill="#f1f5f8"/>
<path id="Union_6" data-name="Union 6" d="M-2631.1,1081.8v-1.6H-8230.9V.022H-2631.1V0H-1871.4s-187.845,197.448-91.626,488.844c49.167,148.9,96.309,256.289,104.683,362.118,7.979,100.852-57.98,201.711-168.644,254.286-65.858,31.29-144.552,42.382-223.028,42.383C-2441.2,1147.632-2631.1,1081.8-2631.1,1081.8Z" transform="translate(3259.524 0.803)" fill="url(#linear-gradient)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.7 KiB

View File

@@ -18,7 +18,7 @@
</Dropdown> </Dropdown>
</template> </template>
<script lang="ts"> <script lang="ts">
import type { LocaleType } from '/@/locales/types'; import type { LocaleType } from '/#/config';
import type { DropMenu } from '/@/components/Dropdown'; import type { DropMenu } from '/@/components/Dropdown';
import { defineComponent, ref, watchEffect, unref, computed } from 'vue'; import { defineComponent, ref, watchEffect, unref, computed } from 'vue';
@@ -26,7 +26,7 @@
import Icon from '/@/components/Icon'; import Icon from '/@/components/Icon';
import { useLocale } from '/@/locales/useLocale'; import { useLocale } from '/@/locales/useLocale';
import { useLocaleSetting } from '/@/hooks/setting/useLocaleSetting'; import { localeList } from '/@/settings/localeSetting';
import { useDesign } from '/@/hooks/web/useDesign'; import { useDesign } from '/@/hooks/web/useDesign';
import { propTypes } from '/@/utils/propTypes'; import { propTypes } from '/@/utils/propTypes';
@@ -44,9 +44,7 @@
const { prefixCls } = useDesign('app-locale-picker'); const { prefixCls } = useDesign('app-locale-picker');
const { localeList } = useLocaleSetting(); const { changeLocale, getLocale } = useLocale();
const { changeLocale, getLang } = useLocale();
const getLangText = computed(() => { const getLangText = computed(() => {
const key = selectedKeys.value[0]; const key = selectedKeys.value[0];
@@ -55,16 +53,17 @@
}); });
watchEffect(() => { watchEffect(() => {
selectedKeys.value = [unref(getLang)]; selectedKeys.value = [unref(getLocale)];
}); });
function toggleLocale(lang: LocaleType | string) { async function toggleLocale(lang: LocaleType | string) {
changeLocale(lang as LocaleType); await changeLocale(lang as LocaleType);
selectedKeys.value = [lang as string]; selectedKeys.value = [lang as string];
props.reload && location.reload(); props.reload && location.reload();
} }
function handleMenuEvent(menu: DropMenu) { function handleMenuEvent(menu: DropMenu) {
if (unref(getLocale) === menu.event) return;
toggleLocale(menu.event as string); toggleLocale(menu.event as string);
} }

View File

@@ -10,8 +10,13 @@
> >
<img src="../../../assets/images/logo.png" /> <img src="../../../assets/images/logo.png" />
<div <div
class="ml-2 truncate xs:opacity-0 md:opacity-100" class="ml-2 truncate md:opacity-100"
:class="`${prefixCls}__title`" :class="[
`${prefixCls}__title`,
{
'xs:opacity-0': !alwaysShowTitle,
},
]"
v-show="showTitle" v-show="showTitle"
> >
{{ title }} {{ title }}
@@ -38,6 +43,7 @@
theme: propTypes.oneOf(['light', 'dark']), theme: propTypes.oneOf(['light', 'dark']),
// Whether to show title // Whether to show title
showTitle: propTypes.bool.def(true), showTitle: propTypes.bool.def(true),
alwaysShowTitle: propTypes.bool.def(false),
}, },
setup() { setup() {
const { prefixCls } = useDesign('app-logo'); const { prefixCls } = useDesign('app-logo');

View File

@@ -4,20 +4,21 @@
--> -->
<template> <template>
<span :class="getClass"> <span :class="getClass">
<RightOutlined /> <Icon icon="ion:chevron-forward" :style="$attrs.iconStyle" />
</span> </span>
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent, computed } from 'vue'; import { defineComponent, computed } from 'vue';
import { RightOutlined } from '@ant-design/icons-vue';
import { useDesign } from '/@/hooks/web/useDesign'; import { useDesign } from '/@/hooks/web/useDesign';
import { propTypes } from '/@/utils/propTypes'; import { propTypes } from '/@/utils/propTypes';
import { Icon } from '/@/components/Icon';
export default defineComponent({ export default defineComponent({
name: 'BasicArrow', name: 'BasicArrow',
components: { RightOutlined }, components: { Icon },
props: { props: {
// Expand contract, expand by default // Expand contract, expand by default
expand: propTypes.bool, expand: propTypes.bool,

View File

@@ -36,7 +36,7 @@
import CollapseHeader from './CollapseHeader.vue'; import CollapseHeader from './CollapseHeader.vue';
import LazyContainer from '../LazyContainer.vue'; import LazyContainer from '../LazyContainer.vue';
import { triggerWindowResize } from '/@/utils/event/triggerWindowResizeEvent'; import { triggerWindowResize } from '/@/utils/event';
// hook // hook
import { useTimeoutFn } from '/@/hooks/core/useTimeout'; import { useTimeoutFn } from '/@/hooks/core/useTimeout';
import { propTypes } from '/@/utils/propTypes'; import { propTypes } from '/@/utils/propTypes';

View File

@@ -0,0 +1,4 @@
import CountButton from './src/CountButton.vue';
import CountdownInput from './src/CountdownInput.vue';
export { CountdownInput, CountButton };

View File

@@ -0,0 +1,57 @@
<template>
<Button v-bind="$attrs" :disabled="isStart" @click="handleStart" :loading="loading">
{{
!isStart
? t('component.countdown.normalText')
: t('component.countdown.sendText', [currentCount])
}}
</Button>
</template>
<script lang="ts">
import { defineComponent, ref, PropType } from 'vue';
import { Button } from 'ant-design-vue';
import { useCountdown } from './useCountdown';
import { isFunction } from '/@/utils/is';
import { useI18n } from '/@/hooks/web/useI18n';
export default defineComponent({
name: 'CountButton',
components: { Button },
props: {
count: {
type: Number,
default: 60,
},
beforeStartFunc: {
type: Function as PropType<() => boolean>,
default: null,
},
},
setup(props) {
const loading = ref(false);
const { currentCount, isStart, start } = useCountdown(props.count);
const { t } = useI18n();
/**
* @description: Judge whether there is an external function before execution, and decide whether to start after execution
*/
async function handleStart() {
const { beforeStartFunc } = props;
if (beforeStartFunc && isFunction(beforeStartFunc)) {
loading.value = true;
try {
const canStart = await beforeStartFunc();
canStart && start();
} finally {
loading.value = false;
}
} else {
start();
}
}
return { handleStart, isStart, currentCount, loading, t };
},
});
</script>

View File

@@ -0,0 +1,52 @@
<template>
<AInput v-bind="$attrs" :class="prefixCls" :size="size">
<template #addonAfter>
<CountButton :size="size" :count="count" :beforeStartFunc="sendCodeApi" />
</template>
</AInput>
</template>
<script lang="ts">
import { defineComponent, PropType } from 'vue';
import { Input } from 'ant-design-vue';
import CountButton from './CountButton.vue';
import { propTypes } from '/@/utils/propTypes';
import { useDesign } from '/@/hooks/web/useDesign';
import { useRuleFormItem } from '/@/hooks/component/useFormItem';
export default defineComponent({
name: 'CountDownInput',
components: { [Input.name]: Input, CountButton },
props: {
value: propTypes.string,
size: propTypes.oneOf(['default', 'large', 'small']),
count: propTypes.number.def(60),
sendCodeApi: {
type: Function as PropType<() => boolean>,
default: null,
},
},
setup(props) {
const { prefixCls } = useDesign('countdown-input');
const [state] = useRuleFormItem(props);
return { prefixCls, state };
},
});
</script>
<style lang="less">
@prefix-cls: ~'@{namespace}-countdown-input';
.@{prefix-cls} {
.ant-input-group-addon {
padding-right: 0;
background-color: transparent;
border: none;
button {
font-size: 14px;
}
}
}
</style>

View File

@@ -0,0 +1,51 @@
import { ref, unref } from 'vue';
import { tryOnUnmounted } from '/@/utils/helper/vueHelper';
export function useCountdown(count: number) {
const currentCount = ref(count);
const isStart = ref(false);
let timerId: ReturnType<typeof setInterval> | null;
function clear() {
timerId && window.clearInterval(timerId);
}
function stop() {
isStart.value = false;
timerId = null;
clear();
}
function start() {
if (unref(isStart) || !!timerId) {
return;
}
isStart.value = true;
timerId = setInterval(() => {
if (unref(currentCount) === 1) {
stop();
currentCount.value = count;
} else {
currentCount.value -= 1;
}
}, 1000);
}
function reset() {
currentCount.value = count;
stop();
}
function restart() {
reset();
start();
}
tryOnUnmounted(() => {
reset();
});
return { start, reset, restart, clear, stop, currentCount, isStart };
}

View File

@@ -6,7 +6,11 @@
<template #overlay> <template #overlay>
<a-menu :selectedKeys="selectedKeys"> <a-menu :selectedKeys="selectedKeys">
<template v-for="item in getMenuList" :key="`${item.event}`"> <template v-for="item in getMenuList" :key="`${item.event}`">
<a-menu-item @click="handleClickMenu(item)" :disabled="item.disabled"> <a-menu-item
v-bind="getAttr(item.event)"
@click="handleClickMenu(item)"
:disabled="item.disabled"
>
<Icon :icon="item.icon" v-if="item.icon" /> <Icon :icon="item.icon" v-if="item.icon" />
<span class="ml-1">{{ item.text }}</span> <span class="ml-1">{{ item.text }}</span>
</a-menu-item> </a-menu-item>
@@ -66,7 +70,11 @@
item.onClick?.(); item.onClick?.();
} }
return { handleClickMenu, getMenuList }; return {
handleClickMenu,
getMenuList,
getAttr: (key: string) => ({ key }),
};
}, },
}); });
</script> </script>

View File

@@ -21,6 +21,8 @@ import {
import RadioButtonGroup from './components/RadioButtonGroup.vue'; import RadioButtonGroup from './components/RadioButtonGroup.vue';
import ApiSelect from './components/ApiSelect.vue'; import ApiSelect from './components/ApiSelect.vue';
import { BasicUpload } from '/@/components/Upload'; import { BasicUpload } from '/@/components/Upload';
import { StrengthMeter } from '/@/components/StrengthMeter';
import { IconPicker } from '/@/components/Icon';
const componentMap = new Map<ComponentType, Component>(); const componentMap = new Map<ComponentType, Component>();
@@ -51,6 +53,8 @@ componentMap.set('MonthPicker', DatePicker.MonthPicker);
componentMap.set('RangePicker', DatePicker.RangePicker); componentMap.set('RangePicker', DatePicker.RangePicker);
componentMap.set('WeekPicker', DatePicker.WeekPicker); componentMap.set('WeekPicker', DatePicker.WeekPicker);
componentMap.set('TimePicker', TimePicker); componentMap.set('TimePicker', TimePicker);
componentMap.set('StrengthMeter', StrengthMeter);
componentMap.set('IconPicker', IconPicker);
componentMap.set('Upload', BasicUpload); componentMap.set('Upload', BasicUpload);

View File

@@ -311,11 +311,12 @@ export default defineComponent({
const realColProps = { ...baseColProps, ...colProps }; const realColProps = { ...baseColProps, ...colProps };
const { isIfShow, isShow } = getShow(); const { isIfShow, isShow } = getShow();
const values = unref(getValues);
const getContent = () => { const getContent = () => {
return colSlot return colSlot
? getSlot(slots, colSlot, unref(getValues)) ? getSlot(slots, colSlot, values)
: renderColContent : renderColContent
? renderColContent(unref(getValues)) ? renderColContent(values)
: renderItem(); : renderItem();
}; };

View File

@@ -7,7 +7,7 @@ import { getDynamicProps } from '/@/utils';
import type { FormProps, FormActionType, UseFormReturnType, FormSchema } from '../types/form'; import type { FormProps, FormActionType, UseFormReturnType, FormSchema } from '../types/form';
import type { NamePath } from 'ant-design-vue/lib/form/interface'; import type { NamePath } from 'ant-design-vue/lib/form/interface';
import type { DynamicProps } from '/@/types/utils'; import type { DynamicProps } from '/#/utils';
export declare type ValidateFields = (nameList?: NamePath[]) => Promise<Recordable>; export declare type ValidateFields = (nameList?: NamePath[]) => Promise<Recordable>;

View File

@@ -5,10 +5,10 @@ import type { NamePath } from 'ant-design-vue/lib/form/interface';
import { unref, toRaw } from 'vue'; import { unref, toRaw } from 'vue';
import { isArray, isFunction, isObject, isString } from '/@/utils/is'; import { isArray, isFunction, isObject, isString } from '/@/utils/is';
import { deepMerge, unique } from '/@/utils'; import { deepMerge } from '/@/utils';
import { dateItemType, handleInputNumberValue } from '../helper'; import { dateItemType, handleInputNumberValue } from '../helper';
import { dateUtil } from '/@/utils/dateUtil'; import { dateUtil } from '/@/utils/dateUtil';
import { cloneDeep } from 'lodash-es'; import { cloneDeep, uniqBy } from 'lodash-es';
import { error } from '/@/utils/log'; import { error } from '/@/utils/log';
interface UseFormActionContext { interface UseFormActionContext {
@@ -160,7 +160,7 @@ export function useFormEvents({
} }
}); });
}); });
schemaRef.value = unique(schema, 'field'); schemaRef.value = uniqBy(schema, 'field');
} }
function getFieldsValue(): Recordable { function getFieldsValue(): Recordable {

View File

@@ -91,7 +91,6 @@ export type ComponentType =
| 'Select' | 'Select'
| 'ApiSelect' | 'ApiSelect'
| 'SelectOptGroup' | 'SelectOptGroup'
| 'SelectOption'
| 'TreeSelect' | 'TreeSelect'
| 'Transfer' | 'Transfer'
| 'RadioButtonGroup' | 'RadioButtonGroup'
@@ -108,4 +107,5 @@ export type ComponentType =
| 'Switch' | 'Switch'
| 'StrengthMeter' | 'StrengthMeter'
| 'Upload' | 'Upload'
| 'IconPicker'
| 'Render'; | 'Render';

View File

@@ -0,0 +1,793 @@
export default {
prefix: 'ant-design',
icons: [
'account-book-filled',
'account-book-outlined',
'account-book-twotone',
'aim-outlined',
'alert-filled',
'alert-outlined',
'alert-twotone',
'alibaba-outlined',
'align-center-outlined',
'align-left-outlined',
'align-right-outlined',
'alipay-circle-filled',
'alipay-circle-outlined',
'alipay-outlined',
'alipay-square-filled',
'aliwangwang-filled',
'aliwangwang-outlined',
'aliyun-outlined',
'amazon-circle-filled',
'amazon-outlined',
'amazon-square-filled',
'android-filled',
'android-outlined',
'ant-cloud-outlined',
'ant-design-outlined',
'apartment-outlined',
'api-filled',
'api-outlined',
'api-twotone',
'apple-filled',
'apple-outlined',
'appstore-add-outlined',
'appstore-filled',
'appstore-outlined',
'appstore-twotone',
'area-chart-outlined',
'arrow-down-outlined',
'arrow-left-outlined',
'arrow-right-outlined',
'arrow-up-outlined',
'arrows-alt-outlined',
'audio-filled',
'audio-muted-outlined',
'audio-outlined',
'audio-twotone',
'audit-outlined',
'backward-filled',
'backward-outlined',
'bank-filled',
'bank-outlined',
'bank-twotone',
'bar-chart-outlined',
'barcode-outlined',
'bars-outlined',
'behance-circle-filled',
'behance-outlined',
'behance-square-filled',
'behance-square-outlined',
'bell-filled',
'bell-outlined',
'bell-twotone',
'bg-colors-outlined',
'block-outlined',
'bold-outlined',
'book-filled',
'book-outlined',
'book-twotone',
'border-bottom-outlined',
'border-horizontal-outlined',
'border-inner-outlined',
'border-left-outlined',
'border-outer-outlined',
'border-outlined',
'border-right-outlined',
'border-top-outlined',
'border-verticle-outlined',
'borderless-table-outlined',
'box-plot-filled',
'box-plot-outlined',
'box-plot-twotone',
'branches-outlined',
'bug-filled',
'bug-outlined',
'bug-twotone',
'build-filled',
'build-outlined',
'build-twotone',
'bulb-filled',
'bulb-outlined',
'bulb-twotone',
'calculator-filled',
'calculator-outlined',
'calculator-twotone',
'calendar-filled',
'calendar-outlined',
'calendar-twotone',
'camera-filled',
'camera-outlined',
'camera-twotone',
'car-filled',
'car-outlined',
'car-twotone',
'caret-down-filled',
'caret-down-outlined',
'caret-left-filled',
'caret-left-outlined',
'caret-right-filled',
'caret-right-outlined',
'caret-up-filled',
'caret-up-outlined',
'carry-out-filled',
'carry-out-outlined',
'carry-out-twotone',
'check-circle-filled',
'check-circle-outlined',
'check-circle-twotone',
'check-outlined',
'check-square-filled',
'check-square-outlined',
'check-square-twotone',
'chrome-filled',
'chrome-outlined',
'ci-circle-filled',
'ci-circle-outlined',
'ci-circle-twotone',
'ci-outlined',
'ci-twotone',
'clear-outlined',
'clock-circle-filled',
'clock-circle-outlined',
'clock-circle-twotone',
'close-circle-filled',
'close-circle-outlined',
'close-circle-twotone',
'close-outlined',
'close-square-filled',
'close-square-outlined',
'close-square-twotone',
'cloud-download-outlined',
'cloud-filled',
'cloud-outlined',
'cloud-server-outlined',
'cloud-sync-outlined',
'cloud-twotone',
'cloud-upload-outlined',
'cluster-outlined',
'code-filled',
'code-outlined',
'code-sandbox-circle-filled',
'code-sandbox-outlined',
'code-sandbox-square-filled',
'code-twotone',
'codepen-circle-filled',
'codepen-circle-outlined',
'codepen-outlined',
'codepen-square-filled',
'coffee-outlined',
'column-height-outlined',
'column-width-outlined',
'comment-outlined',
'compass-filled',
'compass-outlined',
'compass-twotone',
'compress-outlined',
'console-sql-outlined',
'contacts-filled',
'contacts-outlined',
'contacts-twotone',
'container-filled',
'container-outlined',
'container-twotone',
'control-filled',
'control-outlined',
'control-twotone',
'copy-filled',
'copy-outlined',
'copy-twotone',
'copyright-circle-filled',
'copyright-circle-outlined',
'copyright-circle-twotone',
'copyright-outlined',
'copyright-twotone',
'credit-card-filled',
'credit-card-outlined',
'credit-card-twotone',
'crown-filled',
'crown-outlined',
'crown-twotone',
'customer-service-filled',
'customer-service-outlined',
'customer-service-twotone',
'dash-outlined',
'dashboard-filled',
'dashboard-outlined',
'dashboard-twotone',
'database-filled',
'database-outlined',
'database-twotone',
'delete-column-outlined',
'delete-filled',
'delete-outlined',
'delete-row-outlined',
'delete-twotone',
'delivered-procedure-outlined',
'deployment-unit-outlined',
'desktop-outlined',
'diff-filled',
'diff-outlined',
'diff-twotone',
'dingding-outlined',
'dingtalk-circle-filled',
'dingtalk-outlined',
'dingtalk-square-filled',
'disconnect-outlined',
'dislike-filled',
'dislike-outlined',
'dislike-twotone',
'dollar-circle-filled',
'dollar-circle-outlined',
'dollar-circle-twotone',
'dollar-outlined',
'dollar-twotone',
'dot-chart-outlined',
'double-left-outlined',
'double-right-outlined',
'down-circle-filled',
'down-circle-outlined',
'down-circle-twotone',
'down-outlined',
'down-square-filled',
'down-square-outlined',
'down-square-twotone',
'download-outlined',
'drag-outlined',
'dribbble-circle-filled',
'dribbble-outlined',
'dribbble-square-filled',
'dribbble-square-outlined',
'dropbox-circle-filled',
'dropbox-outlined',
'dropbox-square-filled',
'edit-filled',
'edit-outlined',
'edit-twotone',
'ellipsis-outlined',
'enter-outlined',
'environment-filled',
'environment-outlined',
'environment-twotone',
'euro-circle-filled',
'euro-circle-outlined',
'euro-circle-twotone',
'euro-outlined',
'euro-twotone',
'exception-outlined',
'exclamation-circle-filled',
'exclamation-circle-outlined',
'exclamation-circle-twotone',
'exclamation-outlined',
'expand-alt-outlined',
'expand-outlined',
'experiment-filled',
'experiment-outlined',
'experiment-twotone',
'export-outlined',
'eye-filled',
'eye-invisible-filled',
'eye-invisible-outlined',
'eye-invisible-twotone',
'eye-outlined',
'eye-twotone',
'facebook-filled',
'facebook-outlined',
'fall-outlined',
'fast-backward-filled',
'fast-backward-outlined',
'fast-forward-filled',
'fast-forward-outlined',
'field-binary-outlined',
'field-number-outlined',
'field-string-outlined',
'field-time-outlined',
'file-add-filled',
'file-add-outlined',
'file-add-twotone',
'file-done-outlined',
'file-excel-filled',
'file-excel-outlined',
'file-excel-twotone',
'file-exclamation-filled',
'file-exclamation-outlined',
'file-exclamation-twotone',
'file-filled',
'file-gif-outlined',
'file-image-filled',
'file-image-outlined',
'file-image-twotone',
'file-jpg-outlined',
'file-markdown-filled',
'file-markdown-outlined',
'file-markdown-twotone',
'file-outlined',
'file-pdf-filled',
'file-pdf-outlined',
'file-pdf-twotone',
'file-ppt-filled',
'file-ppt-outlined',
'file-ppt-twotone',
'file-protect-outlined',
'file-search-outlined',
'file-sync-outlined',
'file-text-filled',
'file-text-outlined',
'file-text-twotone',
'file-twotone',
'file-unknown-filled',
'file-unknown-outlined',
'file-unknown-twotone',
'file-word-filled',
'file-word-outlined',
'file-word-twotone',
'file-zip-filled',
'file-zip-outlined',
'file-zip-twotone',
'filter-filled',
'filter-outlined',
'filter-twotone',
'fire-filled',
'fire-outlined',
'fire-twotone',
'flag-filled',
'flag-outlined',
'flag-twotone',
'folder-add-filled',
'folder-add-outlined',
'folder-add-twotone',
'folder-filled',
'folder-open-filled',
'folder-open-outlined',
'folder-open-twotone',
'folder-outlined',
'folder-twotone',
'folder-view-outlined',
'font-colors-outlined',
'font-size-outlined',
'fork-outlined',
'form-outlined',
'format-painter-filled',
'format-painter-outlined',
'forward-filled',
'forward-outlined',
'frown-filled',
'frown-outlined',
'frown-twotone',
'fullscreen-exit-outlined',
'fullscreen-outlined',
'function-outlined',
'fund-filled',
'fund-outlined',
'fund-projection-screen-outlined',
'fund-twotone',
'fund-view-outlined',
'funnel-plot-filled',
'funnel-plot-outlined',
'funnel-plot-twotone',
'gateway-outlined',
'gif-outlined',
'gift-filled',
'gift-outlined',
'gift-twotone',
'github-filled',
'github-outlined',
'gitlab-filled',
'gitlab-outlined',
'global-outlined',
'gold-filled',
'gold-outlined',
'gold-twotone',
'golden-filled',
'google-circle-filled',
'google-outlined',
'google-plus-circle-filled',
'google-plus-outlined',
'google-plus-square-filled',
'google-square-filled',
'group-outlined',
'hdd-filled',
'hdd-outlined',
'hdd-twotone',
'heart-filled',
'heart-outlined',
'heart-twotone',
'heat-map-outlined',
'highlight-filled',
'highlight-outlined',
'highlight-twotone',
'history-outlined',
'home-filled',
'home-outlined',
'home-twotone',
'hourglass-filled',
'hourglass-outlined',
'hourglass-twotone',
'html5-filled',
'html5-outlined',
'html5-twotone',
'idcard-filled',
'idcard-outlined',
'idcard-twotone',
'ie-circle-filled',
'ie-outlined',
'ie-square-filled',
'import-outlined',
'inbox-outlined',
'info-circle-filled',
'info-circle-outlined',
'info-circle-twotone',
'info-outlined',
'insert-row-above-outlined',
'insert-row-below-outlined',
'insert-row-left-outlined',
'insert-row-right-outlined',
'instagram-filled',
'instagram-outlined',
'insurance-filled',
'insurance-outlined',
'insurance-twotone',
'interaction-filled',
'interaction-outlined',
'interaction-twotone',
'issues-close-outlined',
'italic-outlined',
'key-outlined',
'laptop-outlined',
'layout-filled',
'layout-outlined',
'layout-twotone',
'left-circle-filled',
'left-circle-outlined',
'left-circle-twotone',
'left-outlined',
'left-square-filled',
'left-square-outlined',
'left-square-twotone',
'like-filled',
'like-outlined',
'like-twotone',
'line-chart-outlined',
'line-height-outlined',
'line-outlined',
'link-outlined',
'linkedin-filled',
'linkedin-outlined',
'loading-3-quarters-outlined',
'loading-outlined',
'lock-filled',
'lock-outlined',
'lock-twotone',
'login-outlined',
'logout-outlined',
'mac-command-filled',
'mac-command-outlined',
'mail-filled',
'mail-outlined',
'mail-twotone',
'man-outlined',
'medicine-box-filled',
'medicine-box-outlined',
'medicine-box-twotone',
'medium-circle-filled',
'medium-outlined',
'medium-square-filled',
'medium-workmark-outlined',
'meh-filled',
'meh-outlined',
'meh-twotone',
'menu-fold-outlined',
'menu-outlined',
'menu-unfold-outlined',
'merge-cells-outlined',
'message-filled',
'message-outlined',
'message-twotone',
'minus-circle-filled',
'minus-circle-outlined',
'minus-circle-twotone',
'minus-outlined',
'minus-square-filled',
'minus-square-outlined',
'minus-square-twotone',
'mobile-filled',
'mobile-outlined',
'mobile-twotone',
'money-collect-filled',
'money-collect-outlined',
'money-collect-twotone',
'monitor-outlined',
'more-outlined',
'node-collapse-outlined',
'node-expand-outlined',
'node-index-outlined',
'notification-filled',
'notification-outlined',
'notification-twotone',
'number-outlined',
'one-to-one-outlined',
'ordered-list-outlined',
'paper-clip-outlined',
'partition-outlined',
'pause-circle-filled',
'pause-circle-outlined',
'pause-circle-twotone',
'pause-outlined',
'pay-circle-filled',
'pay-circle-outlined',
'percentage-outlined',
'phone-filled',
'phone-outlined',
'phone-twotone',
'pic-center-outlined',
'pic-left-outlined',
'pic-right-outlined',
'picture-filled',
'picture-outlined',
'picture-twotone',
'pie-chart-filled',
'pie-chart-outlined',
'pie-chart-twotone',
'play-circle-filled',
'play-circle-outlined',
'play-circle-twotone',
'play-square-filled',
'play-square-outlined',
'play-square-twotone',
'plus-circle-filled',
'plus-circle-outlined',
'plus-circle-twotone',
'plus-outlined',
'plus-square-filled',
'plus-square-outlined',
'plus-square-twotone',
'pound-circle-filled',
'pound-circle-outlined',
'pound-circle-twotone',
'pound-outlined',
'poweroff-outlined',
'printer-filled',
'printer-outlined',
'printer-twotone',
'profile-filled',
'profile-outlined',
'profile-twotone',
'project-filled',
'project-outlined',
'project-twotone',
'property-safety-filled',
'property-safety-outlined',
'property-safety-twotone',
'pull-request-outlined',
'pushpin-filled',
'pushpin-outlined',
'pushpin-twotone',
'qq-circle-filled',
'qq-outlined',
'qq-square-filled',
'qrcode-outlined',
'question-circle-filled',
'question-circle-outlined',
'question-circle-twotone',
'question-outlined',
'radar-chart-outlined',
'radius-bottomleft-outlined',
'radius-bottomright-outlined',
'radius-setting-outlined',
'radius-upleft-outlined',
'radius-upright-outlined',
'read-filled',
'read-outlined',
'reconciliation-filled',
'reconciliation-outlined',
'reconciliation-twotone',
'red-envelope-filled',
'red-envelope-outlined',
'red-envelope-twotone',
'reddit-circle-filled',
'reddit-outlined',
'reddit-square-filled',
'redo-outlined',
'reload-outlined',
'rest-filled',
'rest-outlined',
'rest-twotone',
'retweet-outlined',
'right-circle-filled',
'right-circle-outlined',
'right-circle-twotone',
'right-outlined',
'right-square-filled',
'right-square-outlined',
'right-square-twotone',
'rise-outlined',
'robot-filled',
'robot-outlined',
'rocket-filled',
'rocket-outlined',
'rocket-twotone',
'rollback-outlined',
'rotate-left-outlined',
'rotate-right-outlined',
'safety-certificate-filled',
'safety-certificate-outlined',
'safety-certificate-twotone',
'safety-outlined',
'save-filled',
'save-outlined',
'save-twotone',
'scan-outlined',
'schedule-filled',
'schedule-outlined',
'schedule-twotone',
'scissor-outlined',
'search-outlined',
'security-scan-filled',
'security-scan-outlined',
'security-scan-twotone',
'select-outlined',
'send-outlined',
'setting-filled',
'setting-outlined',
'setting-twotone',
'shake-outlined',
'share-alt-outlined',
'shop-filled',
'shop-outlined',
'shop-twotone',
'shopping-cart-outlined',
'shopping-filled',
'shopping-outlined',
'shopping-twotone',
'shrink-outlined',
'signal-filled',
'sisternode-outlined',
'sketch-circle-filled',
'sketch-outlined',
'sketch-square-filled',
'skin-filled',
'skin-outlined',
'skin-twotone',
'skype-filled',
'skype-outlined',
'slack-circle-filled',
'slack-outlined',
'slack-square-filled',
'slack-square-outlined',
'sliders-filled',
'sliders-outlined',
'sliders-twotone',
'small-dash-outlined',
'smile-filled',
'smile-outlined',
'smile-twotone',
'snippets-filled',
'snippets-outlined',
'snippets-twotone',
'solution-outlined',
'sort-ascending-outlined',
'sort-descending-outlined',
'sound-filled',
'sound-outlined',
'sound-twotone',
'split-cells-outlined',
'star-filled',
'star-outlined',
'star-twotone',
'step-backward-filled',
'step-backward-outlined',
'step-forward-filled',
'step-forward-outlined',
'stock-outlined',
'stop-filled',
'stop-outlined',
'stop-twotone',
'strikethrough-outlined',
'subnode-outlined',
'swap-left-outlined',
'swap-outlined',
'swap-right-outlined',
'switcher-filled',
'switcher-outlined',
'switcher-twotone',
'sync-outlined',
'table-outlined',
'tablet-filled',
'tablet-outlined',
'tablet-twotone',
'tag-filled',
'tag-outlined',
'tag-twotone',
'tags-filled',
'tags-outlined',
'tags-twotone',
'taobao-circle-filled',
'taobao-circle-outlined',
'taobao-outlined',
'taobao-square-filled',
'team-outlined',
'thunderbolt-filled',
'thunderbolt-outlined',
'thunderbolt-twotone',
'to-top-outlined',
'tool-filled',
'tool-outlined',
'tool-twotone',
'trademark-circle-filled',
'trademark-circle-outlined',
'trademark-circle-twotone',
'trademark-outlined',
'transaction-outlined',
'translation-outlined',
'trophy-filled',
'trophy-outlined',
'trophy-twotone',
'twitter-circle-filled',
'twitter-outlined',
'twitter-square-filled',
'underline-outlined',
'undo-outlined',
'ungroup-outlined',
'unlock-filled',
'unlock-outlined',
'unlock-twotone',
'unordered-list-outlined',
'up-circle-filled',
'up-circle-outlined',
'up-circle-twotone',
'up-outlined',
'up-square-filled',
'up-square-outlined',
'up-square-twotone',
'upload-outlined',
'usb-filled',
'usb-outlined',
'usb-twotone',
'user-add-outlined',
'user-delete-outlined',
'user-outlined',
'user-switch-outlined',
'usergroup-add-outlined',
'usergroup-delete-outlined',
'verified-outlined',
'vertical-align-bottom-outlined',
'vertical-align-middle-outlined',
'vertical-align-top-outlined',
'vertical-left-outlined',
'vertical-right-outlined',
'video-camera-add-outlined',
'video-camera-filled',
'video-camera-outlined',
'video-camera-twotone',
'wallet-filled',
'wallet-outlined',
'wallet-twotone',
'warning-filled',
'warning-outlined',
'warning-twotone',
'wechat-filled',
'wechat-outlined',
'weibo-circle-filled',
'weibo-circle-outlined',
'weibo-outlined',
'weibo-square-filled',
'weibo-square-outlined',
'whats-app-outlined',
'wifi-outlined',
'windows-filled',
'windows-outlined',
'woman-outlined',
'yahoo-filled',
'yahoo-outlined',
'youtube-filled',
'youtube-outlined',
'yuque-filled',
'yuque-outlined',
'zhihu-circle-filled',
'zhihu-outlined',
'zhihu-square-filled',
'zoom-in-outlined',
'zoom-out-outlined',
],
};

View File

@@ -1,4 +1,9 @@
import Icon from './src/index.vue'; import Icon from './src/index.vue';
// import IconPicker from './src/IconPicker.vue';
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
const IconPicker = createAsyncComponent(() => import('./src/IconPicker.vue'));
export { Icon, IconPicker };
export { Icon };
export default Icon; export default Icon;

View File

@@ -0,0 +1,186 @@
<template>
<a-input
disabled
:style="{ width }"
:placeholder="t('component.icon.placeholder')"
:class="prefixCls"
v-model:value="currentSelect"
>
<template #addonAfter>
<Popover
placement="bottomLeft"
trigger="click"
v-model="visible"
:overlayClassName="`${prefixCls}-popover`"
>
<template #title>
<div class="flex justify-between">
<a-input
:placeholder="t('component.icon.search')"
@change="handleSearchChange"
allowClear
/>
</div>
</template>
<template #content>
<div v-if="getPaginationList.length">
<ScrollContainer class="border border-solid border-t-0">
<ul class="flex flex-wrap px-2">
<li
v-for="icon in getPaginationList"
:key="icon"
:class="currentSelect === icon ? 'bg-primary text-white' : ''"
class="p-2 w-1/8 cursor-pointer mr-1 mt-1 flex justify-center items-center border border-solid hover:bg-primary hover:text-white"
@click="handleClick(icon)"
>
<!-- <Icon :icon="icon" :prefix="prefix" /> -->
<Icon :icon="icon" />
</li>
</ul>
</ScrollContainer>
<div class="flex py-2 items-center justify-center">
<Pagination
showLessItems
size="small"
:pageSize="pageSize"
:total="getTotal"
@change="handlePageChange"
/>
</div>
</div>
<template v-else
><div class="p-5"> <Empty /></div>
</template>
</template>
<Icon :icon="currentSelect || 'ion:apps-outline'" class="cursor-pointer px-2 py-1" />
</Popover>
</template>
</a-input>
</template>
<script lang="ts">
import { defineComponent, ref, watchEffect, watch, unref } from 'vue';
import { useDesign } from '/@/hooks/web/useDesign';
import { ScrollContainer } from '/@/components/Container';
import { Input, Popover, Pagination, Empty } from 'ant-design-vue';
import Icon from './index.vue';
import iconsData from '../data/icons.data';
import { propTypes } from '/@/utils/propTypes';
import { usePagination } from '/@/hooks/web/usePagination';
import { useDebounce } from '/@/hooks/core/useDebounce';
import { useI18n } from '/@/hooks/web/useI18n';
import { useCopyToClipboard } from '/@/hooks/web/useCopyToClipboard';
import { useMessage } from '/@/hooks/web/useMessage';
// import '@iconify/iconify';
function getIcons() {
const data = iconsData as any;
const prefix: string = data?.prefix ?? '';
let result: string[] = [];
if (prefix) {
result = (data?.icons ?? []).map((item) => `${prefix}:${item}`);
} else if (Array.isArray(iconsData)) {
result = iconsData as string[];
}
return result;
}
const icons = getIcons();
export default defineComponent({
name: 'IconPicker',
inheritAttrs: false,
components: { [Input.name]: Input, Icon, Popover, ScrollContainer, Pagination, Empty },
props: {
value: propTypes.string,
width: propTypes.string.def('100%'),
pageSize: propTypes.number.def(140),
copy: propTypes.bool.def(false),
},
emits: ['change'],
setup(props, { emit }) {
const currentSelect = ref('');
const visible = ref(false);
const currentList = ref(icons);
const { prefixCls } = useDesign('icon-picker');
const { t } = useI18n();
const [debounceHandleSearchChange] = useDebounce(handleSearchChange, 100);
const { clipboardRef, isSuccessRef } = useCopyToClipboard(props.value);
const { createMessage } = useMessage();
const { getPaginationList, getTotal, setCurrentPage } = usePagination(
currentList,
props.pageSize
);
watchEffect(() => {
currentSelect.value = props.value;
});
watch(
() => currentSelect.value,
(v) => emit('change', v)
);
function handlePageChange(page: number) {
setCurrentPage(page);
}
function handleClick(icon: string) {
currentSelect.value = icon;
if (props.copy) {
clipboardRef.value = icon;
if (unref(isSuccessRef)) {
createMessage.success(t('component.icon.copy'));
}
}
}
function handleSearchChange(e: ChangeEvent) {
const value = e.target.value;
if (!value) {
setCurrentPage(1);
currentList.value = icons;
return;
}
currentList.value = icons.filter((item) => item.includes(value));
}
return {
t,
prefixCls,
visible,
getTotal,
getPaginationList,
handlePageChange,
handleClick,
currentSelect,
handleSearchChange: debounceHandleSearchChange,
};
},
});
</script>
<style lang="less">
@prefix-cls: ~'@{namespace}-icon-picker';
.@{prefix-cls} {
.ant-input-group-addon {
padding: 0;
}
&-popover {
width: 300px;
.ant-popover-inner-content {
padding: 0;
}
.scrollbar {
height: 220px;
}
}
}
</style>

View File

@@ -16,6 +16,7 @@
import Iconify from '@purge-icons/generated'; import Iconify from '@purge-icons/generated';
import { isString } from '/@/utils/is'; import { isString } from '/@/utils/is';
import { propTypes } from '/@/utils/propTypes'; import { propTypes } from '/@/utils/propTypes';
export default defineComponent({ export default defineComponent({
name: 'GIcon', name: 'GIcon',
props: { props: {
@@ -45,7 +46,6 @@
const icon = unref(getIconRef); const icon = unref(getIconRef);
if (!icon) return; if (!icon) return;
const svg = Iconify.renderSVG(icon, {}); const svg = Iconify.renderSVG(icon, {});
if (svg) { if (svg) {
el.textContent = ''; el.textContent = '';
el.appendChild(svg); el.appendChild(svg);

View File

@@ -34,13 +34,13 @@
const modalFn = useModalContext(); const modalFn = useModalContext();
const { getLang } = useLocale(); const { getLocale } = useLocale();
watchEffect(() => {}); watchEffect(() => {});
const getCurrentLang = computed((): 'zh_CN' | 'en_US' | 'ja_JP' | 'ko_KR' => { const getCurrentLang = computed((): 'zh_CN' | 'en_US' | 'ja_JP' | 'ko_KR' => {
let lang: Lang; let lang: Lang;
switch (unref(getLang)) { switch (unref(getLocale)) {
case 'en': case 'en':
lang = 'en_US'; lang = 'en_US';
break; break;

View File

@@ -110,7 +110,7 @@
listenerLastChangeTab((route) => { listenerLastChangeTab((route) => {
if (route.name === REDIRECT_NAME) return; if (route.name === REDIRECT_NAME) return;
handleMenuChange(route); handleMenuChange(route);
currentActiveMenu.value = route.meta?.currentActiveMenu; currentActiveMenu.value = route.meta?.currentActiveMenu as string;
if (unref(currentActiveMenu)) { if (unref(currentActiveMenu)) {
menuState.selectedKeys = [unref(currentActiveMenu)]; menuState.selectedKeys = [unref(currentActiveMenu)];

View File

@@ -5,7 +5,7 @@ import type { MenuState } from './types';
import { computed, Ref, toRaw } from 'vue'; import { computed, Ref, toRaw } from 'vue';
import { unref } from 'vue'; import { unref } from 'vue';
import { es6Unique } from '/@/utils'; import { uniq } from 'lodash-es';
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting'; import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
import { getAllParentPath } from '/@/router/helper/menuHelper'; import { getAllParentPath } from '/@/router/helper/menuHelper';
import { useTimeoutFn } from '/@/hooks/core/useTimeout'; import { useTimeoutFn } from '/@/hooks/core/useTimeout';
@@ -31,10 +31,7 @@ export function useOpenKeys(
return; return;
} }
if (!unref(accordion)) { if (!unref(accordion)) {
menuState.openKeys = es6Unique([ menuState.openKeys = uniq([...menuState.openKeys, ...getAllParentPath(menuList, path)]);
...menuState.openKeys,
...getAllParentPath(menuList, path),
]);
} else { } else {
menuState.openKeys = getAllParentPath(menuList, path); menuState.openKeys = getAllParentPath(menuList, path);
} }

View File

@@ -10,7 +10,11 @@
</template> </template>
<template #title v-if="!$slots.title"> <template #title v-if="!$slots.title">
<ModalHeader :helpMessage="getProps.helpMessage" :title="getMergeProps.title" /> <ModalHeader
:helpMessage="getProps.helpMessage"
:title="getMergeProps.title"
@dblclick="handleTitleDbClick"
/>
</template> </template>
<template #footer v-if="!$slots.footer"> <template #footer v-if="!$slots.footer">
@@ -28,7 +32,7 @@
ref="modalWrapperRef" ref="modalWrapperRef"
:loading="getProps.loading" :loading="getProps.loading"
:minHeight="getProps.minHeight" :minHeight="getProps.minHeight"
:height="getProps.height" :height="getWrapperHeight"
:visible="visibleRef" :visible="visibleRef"
:modalFooterHeight="footer !== undefined && !footer ? 0 : undefined" :modalFooterHeight="footer !== undefined && !footer ? 0 : undefined"
v-bind="omit(getProps.wrapperProps, 'visible', 'height')" v-bind="omit(getProps.wrapperProps, 'visible', 'height')"
@@ -132,8 +136,19 @@
} }
); );
const getBindValue = computed((): any => { const getBindValue = computed(
return { ...attrs, ...unref(getProps) }; (): Recordable => {
const attr = { ...attrs, ...unref(getProps) };
if (unref(fullScreenRef)) {
return omit(attr, 'height');
}
return attr;
}
);
const getWrapperHeight = computed(() => {
if (unref(fullScreenRef)) return undefined;
return unref(getProps).height;
}); });
watchEffect(() => { watchEffect(() => {
@@ -193,6 +208,12 @@
extHeightRef.value = height; extHeightRef.value = height;
} }
function handleTitleDbClick(e: ChangeEvent) {
if (!props.canFullscreen) return;
e.stopPropagation();
handleFullScreen(e);
}
return { return {
handleCancel, handleCancel,
getBindValue, getBindValue,
@@ -206,6 +227,8 @@
modalWrapperRef, modalWrapperRef,
handleExtHeight, handleExtHeight,
handleHeightChange, handleHeightChange,
handleTitleDbClick,
getWrapperHeight,
}; };
}, },
}); });

View File

@@ -1,4 +1,2 @@
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent'; export { default as PageFooter } from './src/PageFooter.vue';
export const PageFooter = createAsyncComponent(() => import('./src/PageFooter.vue'));
export { default as PageWrapper } from './src/PageWrapper.vue'; export { default as PageWrapper } from './src/PageWrapper.vue';

View File

@@ -41,7 +41,7 @@
border-top: 1px solid #f0f0f0; border-top: 1px solid #f0f0f0;
box-shadow: 0 -6px 16px -8px rgba(0, 0, 0, 0.08), 0 -9px 28px 0 rgba(0, 0, 0, 0.05), box-shadow: 0 -6px 16px -8px rgba(0, 0, 0, 0.08), 0 -9px 28px 0 rgba(0, 0, 0, 0.05),
0 -12px 48px 16px rgba(0, 0, 0, 0.03); 0 -12px 48px 16px rgba(0, 0, 0, 0.03);
transition: width 0.4s; transition: width 0.2s;
&__left { &__left {
flex: 1 1; flex: 1 1;

View File

@@ -1,4 +1,3 @@
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent'; export { default as QrCode } from './src/index.vue';
export const QrCode = createAsyncComponent(() => import('./src/index.vue'));
export * from './src/types'; export * from './src/types';

View File

@@ -17,7 +17,7 @@
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { addResizeListener, removeResizeListener } from '/@/utils/event/resizeEvent'; import { addResizeListener, removeResizeListener } from '/@/utils/event';
import componentSetting from '/@/settings/componentSetting'; import componentSetting from '/@/settings/componentSetting';
const { scrollbar } = componentSetting; const { scrollbar } = componentSetting;
import { toObject } from './util'; import { toObject } from './util';
@@ -29,6 +29,7 @@
nextTick, nextTick,
provide, provide,
computed, computed,
unref,
} from 'vue'; } from 'vue';
import Bar from './bar'; import Bar from './bar';
@@ -73,18 +74,25 @@
provide('scroll-bar-wrap', wrap); provide('scroll-bar-wrap', wrap);
const style = computed(() => {
if (Array.isArray(props.wrapStyle)) {
return toObject(props.wrapStyle);
}
return props.wrapStyle;
});
const handleScroll = () => { const handleScroll = () => {
if (!props.native) { if (!props.native) {
moveY.value = (wrap.value.scrollTop * 100) / wrap.value.clientHeight; moveY.value = (unref(wrap).scrollTop * 100) / unref(wrap).clientHeight;
moveX.value = (wrap.value.scrollLeft * 100) / wrap.value.clientWidth; moveX.value = (unref(wrap).scrollLeft * 100) / unref(wrap).clientWidth;
} }
}; };
const update = () => { const update = () => {
if (!wrap.value) return; if (!unref(wrap)) return;
const heightPercentage = (wrap.value.clientHeight * 100) / wrap.value.scrollHeight; const heightPercentage = (unref(wrap).clientHeight * 100) / unref(wrap).scrollHeight;
const widthPercentage = (wrap.value.clientWidth * 100) / wrap.value.scrollWidth; const widthPercentage = (unref(wrap).clientWidth * 100) / unref(wrap).scrollWidth;
sizeHeight.value = heightPercentage < 100 ? heightPercentage + '%' : ''; sizeHeight.value = heightPercentage < 100 ? heightPercentage + '%' : '';
sizeWidth.value = widthPercentage < 100 ? widthPercentage + '%' : ''; sizeWidth.value = widthPercentage < 100 ? widthPercentage + '%' : '';
@@ -94,25 +102,21 @@
if (props.native) return; if (props.native) return;
nextTick(update); nextTick(update);
if (!props.noresize) { if (!props.noresize) {
addResizeListener(resize.value, update); addResizeListener(unref(resize), update);
addResizeListener(wrap.value, update); addResizeListener(unref(wrap), update);
addEventListener('resize', update);
} }
}); });
onBeforeUnmount(() => { onBeforeUnmount(() => {
if (props.native) return; if (props.native) return;
if (!props.noresize) { if (!props.noresize) {
removeResizeListener(resize.value, update); removeResizeListener(unref(resize), update);
removeResizeListener(wrap.value, update); removeResizeListener(unref(wrap), update);
removeEventListener('resize', update);
} }
}); });
const style = computed(() => {
let style: any = props.wrapStyle;
if (Array.isArray(props.wrapStyle)) {
style = toObject(props.wrapStyle);
}
return style;
});
return { return {
moveX, moveX,
moveY, moveY,

View File

@@ -52,7 +52,6 @@
import { propTypes } from '/@/utils/propTypes'; import { propTypes } from '/@/utils/propTypes';
import { useI18n } from '/@/hooks/web/useI18n'; import { useI18n } from '/@/hooks/web/useI18n';
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent'; import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
const { t } = useI18n();
export default defineComponent({ export default defineComponent({
name: 'SimpleSubMenu', name: 'SimpleSubMenu',
@@ -73,6 +72,7 @@
theme: propTypes.oneOf(['dark', 'light']), theme: propTypes.oneOf(['dark', 'light']),
}, },
setup(props) { setup(props) {
const { t } = useI18n();
const { prefixCls } = useDesign('simple-menu'); const { prefixCls } = useDesign('simple-menu');
const getShowMenu = computed(() => { const getShowMenu = computed(() => {

View File

@@ -35,7 +35,7 @@
&-tag { &-tag {
position: absolute; position: absolute;
top: calc(50% - 10px); top: calc(50% - 8px);
right: 30px; right: 30px;
display: inline-block; display: inline-block;
padding: 2px 3px; padding: 2px 3px;
@@ -51,7 +51,7 @@
} }
&--dot { &--dot {
top: calc(50% - 4px); top: calc(50% - 2px);
width: 6px; width: 6px;
height: 6px; height: 6px;
padding: 0; padding: 0;

View File

@@ -4,8 +4,9 @@ import type { MenuState } from './types';
import { computed, Ref, toRaw } from 'vue'; import { computed, Ref, toRaw } from 'vue';
import { unref } from 'vue'; import { unref } from 'vue';
import { es6Unique } from '/@/utils'; import { uniq } from 'lodash-es';
import { getAllParentPath } from '/@/router/helper/menuHelper'; import { getAllParentPath } from '/@/router/helper/menuHelper';
import { useTimeoutFn } from '/@/hooks/core/useTimeout'; import { useTimeoutFn } from '/@/hooks/core/useTimeout';
export function useOpenKeys( export function useOpenKeys(
@@ -31,7 +32,7 @@ export function useOpenKeys(
} }
const keys = getAllParentPath(menuList, path); const keys = getAllParentPath(menuList, path);
if (!unref(accordion)) { if (!unref(accordion)) {
menuState.openNames = es6Unique([...menuState.openNames, ...keys]); menuState.openNames = uniq([...menuState.openNames, ...keys]);
} else { } else {
menuState.openNames = keys; menuState.openNames = keys;
} }

View File

@@ -1,3 +1 @@
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent'; export { default as StrengthMeter } from './src/index.vue';
export const StrengthMeter = createAsyncComponent(() => import('./src/index.vue'));

View File

@@ -1,5 +1,5 @@
<template> <template>
<div :class="prefixCls"> <div :class="prefixCls" class="relative">
<InputPassword <InputPassword
v-if="showInput" v-if="showInput"
v-bind="$attrs" v-bind="$attrs"
@@ -19,27 +19,20 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { PropType } from 'vue';
import { defineComponent, computed, ref, watch, unref, watchEffect } from 'vue'; import { defineComponent, computed, ref, watch, unref, watchEffect } from 'vue';
import { Input } from 'ant-design-vue'; import { Input } from 'ant-design-vue';
import zxcvbn from 'zxcvbn'; // @ts-ignore
import { propTypes } from '/@/utils/propTypes'; import { zxcvbn } from '@zxcvbn-ts/core';
import { useDesign } from '/@/hooks/web/useDesign'; import { useDesign } from '/@/hooks/web/useDesign';
import { propTypes } from '/@/utils/propTypes';
export default defineComponent({ export default defineComponent({
name: 'StrengthMeter', name: 'StrengthMeter',
components: { InputPassword: Input.Password }, components: { InputPassword: Input.Password },
props: { props: {
value: propTypes.string, value: propTypes.string,
userInputs: {
type: Array as PropType<string[]>,
default: () => [],
},
showInput: propTypes.bool.def(true), showInput: propTypes.bool.def(true),
disabled: propTypes.bool, disabled: propTypes.bool,
}, },
@@ -49,12 +42,10 @@
const { prefixCls } = useDesign('strength-meter'); const { prefixCls } = useDesign('strength-meter');
const getPasswordStrength = computed(() => { const getPasswordStrength = computed(() => {
const { userInputs, disabled } = props; const { disabled } = props;
if (disabled) return null; if (disabled) return -1;
const innerValue = unref(innerValueRef); const innerValue = unref(innerValueRef);
const score = innerValue const score = innerValue ? zxcvbn(unref(innerValueRef)).score : -1;
? zxcvbn(unref(innerValueRef), (userInputs as string[]) || null).score
: null;
emit('score-change', score); emit('score-change', score);
return score; return score;
}); });
@@ -66,6 +57,7 @@
watchEffect(() => { watchEffect(() => {
innerValueRef.value = props.value || ''; innerValueRef.value = props.value || '';
}); });
watch( watch(
() => unref(innerValueRef), () => unref(innerValueRef),
(val) => { (val) => {
@@ -86,14 +78,12 @@
@prefix-cls: ~'@{namespace}-strength-meter'; @prefix-cls: ~'@{namespace}-strength-meter';
.@{prefix-cls} { .@{prefix-cls} {
position: relative;
&-bar { &-bar {
position: relative; position: relative;
height: 4px; height: 6px;
margin: 10px auto 6px; margin: 10px auto 6px;
background: @disabled-color; background: @disabled-color;
border-radius: 3px; border-radius: 6px;
&::before, &::before,
&::after { &::after {

View File

@@ -65,6 +65,7 @@
import { useDesign } from '/@/hooks/web/useDesign'; import { useDesign } from '/@/hooks/web/useDesign';
import { basicProps } from './props'; import { basicProps } from './props';
import expandIcon from './components/ExpandIcon';
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent'; import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
import './style/index.less'; import './style/index.less';
@@ -88,9 +89,11 @@
'edit-end', 'edit-end',
'edit-cancel', 'edit-cancel',
'edit-row-end', 'edit-row-end',
'edit-change',
], ],
setup(props, { attrs, emit, slots }) { setup(props, { attrs, emit, slots }) {
const tableElRef = ref<ComponentRef>(null); const tableElRef = ref<ComponentRef>(null);
const tableData = ref<Recordable[]>([]);
const wrapRef = ref<Nullable<HTMLDivElement>>(null); const wrapRef = ref<Nullable<HTMLDivElement>>(null);
const innerPropsRef = ref<Partial<BasicTableProps>>(); const innerPropsRef = ref<Partial<BasicTableProps>>();
@@ -119,7 +122,7 @@
getSelectRowKeys, getSelectRowKeys,
deleteSelectRowByKey, deleteSelectRowByKey,
setSelectedRowKeys, setSelectedRowKeys,
} = useRowSelection(getProps, emit); } = useRowSelection(getProps, tableData, emit);
const { const {
handleTableChange, handleTableChange,
@@ -134,6 +137,7 @@
} = useDataSource( } = useDataSource(
getProps, getProps,
{ {
tableData,
getPaginationInfo, getPaginationInfo,
setLoading, setLoading,
setPagination, setPagination,
@@ -190,6 +194,7 @@
size: 'middle', size: 'middle',
...attrs, ...attrs,
customRow, customRow,
expandIcon: expandIcon(),
...unref(getProps), ...unref(getProps),
...unref(getHeaderProps), ...unref(getHeaderProps),
scroll: unref(getScrollRef), scroll: unref(getScrollRef),

View File

@@ -0,0 +1,19 @@
import { BasicArrow } from '/@/components/Basic';
export default () => {
return (props: Recordable) => {
if (!props.expandable) {
return <span />;
}
return (
<BasicArrow
class="mr-1"
iconStyle="margin-top: -2px;"
onClick={(e: Event) => {
props.onExpand(props.record, e);
}}
expand={props.expanded}
/>
);
};
};

View File

@@ -75,12 +75,15 @@
Reflect.deleteProperty(columns[index], 'customRender'); Reflect.deleteProperty(columns[index], 'customRender');
} }
} }
if (table.getRowSelection() && hasRowSummary) { if (table.getRowSelection() && hasRowSummary) {
const isFixed = columns.some((col) => col.fixed === 'left');
columns.unshift({ columns.unshift({
width: 60, width: 60,
title: 'selection', title: 'selection',
key: 'selectionKey', key: 'selectionKey',
align: 'center', align: 'center',
...(isFixed ? { fixed: 'left' } : {}),
customRender: ({ record }) => record[SUMMARY_ROW_KEY], customRender: ({ record }) => record[SUMMARY_ROW_KEY],
}); });
} }

View File

@@ -4,7 +4,7 @@
<div :class="`${prefixCls}__toolbar`"> <div :class="`${prefixCls}__toolbar`">
<slot name="toolbar"></slot> <slot name="toolbar"></slot>
<Divider type="vertical" v-if="$slots.toolbar" /> <Divider type="vertical" v-if="$slots.toolbar && showTableSetting" />
<TableSetting :setting="tableSetting" v-if="showTableSetting" /> <TableSetting :setting="tableSetting" v-if="showTableSetting" />
</div> </div>
</template> </template>

View File

@@ -29,21 +29,21 @@
<script lang="ts"> <script lang="ts">
import type { CSSProperties, PropType } from 'vue'; import type { CSSProperties, PropType } from 'vue';
import type { BasicColumn } from '../../types/table'; import type { BasicColumn } from '../../types/table';
import type { EditRecordRow } from './index';
import { defineComponent, ref, unref, nextTick, computed, watchEffect } from 'vue'; import { defineComponent, ref, unref, nextTick, computed, watchEffect, toRaw } from 'vue';
import { FormOutlined, CloseOutlined, CheckOutlined } from '@ant-design/icons-vue'; import { FormOutlined, CloseOutlined, CheckOutlined } from '@ant-design/icons-vue';
import { CellComponent } from './CellComponent';
import { useDesign } from '/@/hooks/web/useDesign'; import { useDesign } from '/@/hooks/web/useDesign';
import { isString, isBoolean, isFunction, isNumber, isArray } from '/@/utils/is'; import { useTableContext } from '../../hooks/useTableContext';
import clickOutside from '/@/directives/clickOutside'; import clickOutside from '/@/directives/clickOutside';
import { CellComponent } from './CellComponent';
import { useTableContext } from '../../hooks/useTableContext';
import { propTypes } from '/@/utils/propTypes'; import { propTypes } from '/@/utils/propTypes';
import { isString, isBoolean, isFunction, isNumber, isArray } from '/@/utils/is';
import { createPlaceholderMessage } from './helper'; import { createPlaceholderMessage } from './helper';
import type { EditRecordRow } from './index';
export default defineComponent({ export default defineComponent({
name: 'EditableCell', name: 'EditableCell',
components: { FormOutlined, CloseOutlined, CheckOutlined, CellComponent }, components: { FormOutlined, CloseOutlined, CheckOutlined, CellComponent },
@@ -136,9 +136,11 @@
if (!component.includes('Select')) { if (!component.includes('Select')) {
return value; return value;
} }
const options: LabelValueOptions = editComponentProps?.options ?? (unref(optionsRef) || []); const options: LabelValueOptions = editComponentProps?.options ?? (unref(optionsRef) || []);
const option = options.find((item) => `${item.value}` === `${value}`); const option = options.find((item) => `${item.value}` === `${value}`);
return option?.label;
return option?.label ?? value;
}); });
const getWrapperStyle = computed( const getWrapperStyle = computed(
@@ -188,6 +190,11 @@
} else if (isString(e) || isBoolean(e) || isNumber(e)) { } else if (isString(e) || isBoolean(e) || isNumber(e)) {
currentValueRef.value = e; currentValueRef.value = e;
} }
table.emit?.('edit-change', {
column: props.column,
value: unref(currentValueRef),
record: toRaw(props.record),
});
handleSubmiRule(); handleSubmiRule();
} }
@@ -220,13 +227,17 @@
return true; return true;
} }
async function handleSubmit(needEmit = true) { async function handleSubmit(needEmit = true, valid = true) {
const isPass = await handleSubmiRule(); if (valid) {
if (!isPass) return false; const isPass = await handleSubmiRule();
if (!isPass) return false;
}
const { column, index } = props; const { column, index } = props;
const { key, dataIndex } = column; const { key, dataIndex } = column;
const value = unref(currentValueRef); const value = unref(currentValueRef);
if (!key || !dataIndex) return; if (!key || !dataIndex) return;
const dataKey = (dataIndex || key) as string; const dataKey = (dataIndex || key) as string;
const record = await table.updateTableData(index, dataKey, value); const record = await table.updateTableData(index, dataKey, value);
@@ -287,15 +298,15 @@
const validFns = (props.record?.validCbs || []).map((fn) => fn()); const validFns = (props.record?.validCbs || []).map((fn) => fn());
const res = await Promise.all(validFns); const res = await Promise.all(validFns);
const pass = res.every((item) => !!item); const pass = res.every((item) => !!item);
if (!pass) return; if (!pass) return;
const submitFns = props.record?.submitCbs || []; const submitFns = props.record?.submitCbs || [];
submitFns.forEach((fn) => fn(false)); submitFns.forEach((fn) => fn(false, false));
table.emit?.('edit-row-end'); table.emit?.('edit-row-end');
return true; return true;
} }
// isArray(props.record?.submitCbs) && props.record?.submitCbs.forEach((fn) => fn());
}; };
} }
@@ -328,10 +339,6 @@
@prefix-cls: ~'@{namespace}-editable-cell'; @prefix-cls: ~'@{namespace}-editable-cell';
.edit-cell-rule-popover { .edit-cell-rule-popover {
// .ant-popover-arrow {
// // border-color: transparent @error-color @error-color transparent !important;
// }
.ant-popover-inner-content { .ant-popover-inner-content {
padding: 4px 8px; padding: 4px 8px;
color: @error-color; color: @error-color;
@@ -346,6 +353,10 @@
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
> .ant-select {
min-width: calc(100% - 50px);
}
} }
&__icon { &__icon {
@@ -359,8 +370,6 @@
} }
&__normal { &__normal {
padding-right: 48px;
&-icon { &-icon {
position: absolute; position: absolute;
top: 4px; top: 4px;

View File

@@ -3,8 +3,8 @@
<template #title> <template #title>
<span>{{ t('component.table.settingColumn') }}</span> <span>{{ t('component.table.settingColumn') }}</span>
</template> </template>
<!-- :getPopupContainer="getPopupContainer" -->
<Popover <Popover
:getPopupContainer="getPopupContainer"
placement="bottomLeft" placement="bottomLeft"
trigger="click" trigger="click"
@visibleChange="handleVisibleChange" @visibleChange="handleVisibleChange"

View File

@@ -2,9 +2,7 @@
<div class="table-settings"> <div class="table-settings">
<RedoSetting v-if="getSetting.size" /> <RedoSetting v-if="getSetting.size" />
<SizeSetting v-if="getSetting.redo" /> <SizeSetting v-if="getSetting.redo" />
<ColumnSetting v-if="getSetting.setting" /> <ColumnSetting v-if="getSetting.setting" />
<FullScreenSetting v-if="getSetting.fullScreen" /> <FullScreenSetting v-if="getSetting.fullScreen" />
</div> </div>
</template> </template>
@@ -37,7 +35,7 @@
redo: true, redo: true,
size: true, size: true,
setting: true, setting: true,
fullScreen: true, fullScreen: false,
...props.setting, ...props.setting,
}; };
} }

View File

@@ -45,7 +45,6 @@ export function useCustomRow(
if (!key) return; if (!key) return;
const isCheckbox = rowSelection.type === 'checkbox'; const isCheckbox = rowSelection.type === 'checkbox';
if (isCheckbox) { if (isCheckbox) {
if (!keys.includes(key)) { if (!keys.includes(key)) {
setSelectedRowKeys([...keys, key]); setSelectedRowKeys([...keys, key]);

View File

@@ -1,7 +1,17 @@
import type { BasicTableProps, FetchParams, SorterResult } from '../types/table'; import type { BasicTableProps, FetchParams, SorterResult } from '../types/table';
import type { PaginationProps } from '../types/pagination'; import type { PaginationProps } from '../types/pagination';
import { ref, unref, ComputedRef, computed, onMounted, watch, reactive } from 'vue'; import {
ref,
unref,
ComputedRef,
computed,
onMounted,
watch,
reactive,
Ref,
watchEffect,
} from 'vue';
import { useTimeoutFn } from '/@/hooks/core/useTimeout'; import { useTimeoutFn } from '/@/hooks/core/useTimeout';
@@ -17,6 +27,7 @@ interface ActionType {
setLoading: (loading: boolean) => void; setLoading: (loading: boolean) => void;
getFieldsValue: () => Recordable; getFieldsValue: () => Recordable;
clearSelectedRowKeys: () => void; clearSelectedRowKeys: () => void;
tableData: Ref<Recordable[]>;
} }
interface SearchState { interface SearchState {
@@ -31,6 +42,7 @@ export function useDataSource(
setLoading, setLoading,
getFieldsValue, getFieldsValue,
clearSelectedRowKeys, clearSelectedRowKeys,
tableData,
}: ActionType, }: ActionType,
emit: EmitType emit: EmitType
) { ) {
@@ -45,6 +57,10 @@ export function useDataSource(
// !api && dataSource && (dataSourceRef.value = dataSource); // !api && dataSource && (dataSourceRef.value = dataSource);
// }); // });
watchEffect(() => {
tableData.value = unref(dataSourceRef);
});
watch( watch(
() => unref(propsRef).dataSource, () => unref(propsRef).dataSource,
() => { () => {

View File

@@ -1,9 +1,13 @@
import type { BasicTableProps, TableRowSelection } from '../types/table'; import type { BasicTableProps, TableRowSelection } from '../types/table';
import { computed, ref, unref, ComputedRef } from 'vue'; import { computed, ref, unref, ComputedRef, Ref, toRaw } from 'vue';
import { ROW_KEY } from '../const';
/* eslint-disable */ export function useRowSelection(
export function useRowSelection(propsRef: ComputedRef<BasicTableProps>, emit: EmitType) { propsRef: ComputedRef<BasicTableProps>,
tableData: Ref<Recordable[]>,
emit: EmitType
) {
const selectedRowKeysRef = ref<string[]>([]); const selectedRowKeysRef = ref<string[]>([]);
const selectedRowRef = ref<Recordable[]>([]); const selectedRowRef = ref<Recordable[]>([]);
@@ -27,8 +31,26 @@ export function useRowSelection(propsRef: ComputedRef<BasicTableProps>, emit: Em
}; };
}); });
const getAutoCreateKey = computed(() => {
return unref(propsRef).autoCreateKey && !unref(propsRef).rowKey;
});
const getRowKey = computed(() => {
const { rowKey } = unref(propsRef);
return unref(getAutoCreateKey) ? ROW_KEY : rowKey;
});
function setSelectedRowKeys(rowKeys: string[]) { function setSelectedRowKeys(rowKeys: string[]) {
selectedRowKeysRef.value = rowKeys; selectedRowKeysRef.value = rowKeys;
const rows = toRaw(unref(tableData)).filter((item) =>
rowKeys.includes(item[unref(getRowKey) as string])
);
selectedRowRef.value = rows;
}
function setSelectedRows(rows: Recordable[]) {
selectedRowRef.value = rows;
} }
function clearSelectedRowKeys() { function clearSelectedRowKeys() {
@@ -65,5 +87,6 @@ export function useRowSelection(propsRef: ComputedRef<BasicTableProps>, emit: Em
setSelectedRowKeys, setSelectedRowKeys,
clearSelectedRowKeys, clearSelectedRowKeys,
deleteSelectRowByKey, deleteSelectRowByKey,
setSelectedRows,
}; };
} }

View File

@@ -1,9 +1,9 @@
import type { BasicTableProps, TableActionType, FetchParams, BasicColumn } from '../types/table'; import type { BasicTableProps, TableActionType, FetchParams, BasicColumn } from '../types/table';
import type { PaginationProps } from '../types/pagination'; import type { PaginationProps } from '../types/pagination';
import type { DynamicProps } from '/@/types/utils'; import type { DynamicProps } from '/#/utils';
import { getDynamicProps } from '/@/utils'; import { getDynamicProps } from '/@/utils';
import { ref, onUnmounted, unref, watch } from 'vue'; import { ref, onUnmounted, unref, watch, toRaw } from 'vue';
import { isProdMode } from '/@/utils/env'; import { isProdMode } from '/@/utils/env';
import { isInSetup } from '/@/utils/helper/vueHelper'; import { isInSetup } from '/@/utils/helper/vueHelper';
import { error } from '/@/utils/log'; import { error } from '/@/utils/log';
@@ -77,11 +77,11 @@ export function useTable(
getTableInstance().setLoading(loading); getTableInstance().setLoading(loading);
}, },
getDataSource: () => { getDataSource: () => {
return getTableInstance().getDataSource(); return toRaw(getTableInstance().getDataSource());
}, },
getColumns: ({ ignoreIndex = false }: { ignoreIndex?: boolean } = {}) => { getColumns: ({ ignoreIndex = false }: { ignoreIndex?: boolean } = {}) => {
const columns = getTableInstance().getColumns({ ignoreIndex }) || []; const columns = getTableInstance().getColumns({ ignoreIndex }) || [];
return columns; return toRaw(columns);
}, },
setColumns: (columns: BasicColumn[]) => { setColumns: (columns: BasicColumn[]) => {
getTableInstance().setColumns(columns); getTableInstance().setColumns(columns);
@@ -96,10 +96,10 @@ export function useTable(
getTableInstance().deleteSelectRowByKey(key); getTableInstance().deleteSelectRowByKey(key);
}, },
getSelectRowKeys: () => { getSelectRowKeys: () => {
return getTableInstance().getSelectRowKeys(); return toRaw(getTableInstance().getSelectRowKeys());
}, },
getSelectRows: () => { getSelectRows: () => {
return getTableInstance().getSelectRows(); return toRaw(getTableInstance().getSelectRows());
}, },
clearSelectedRowKeys: () => { clearSelectedRowKeys: () => {
getTableInstance().clearSelectedRowKeys(); getTableInstance().clearSelectedRowKeys();
@@ -111,16 +111,16 @@ export function useTable(
return getTableInstance().getPaginationRef(); return getTableInstance().getPaginationRef();
}, },
getSize: () => { getSize: () => {
return getTableInstance().getSize(); return toRaw(getTableInstance().getSize());
}, },
updateTableData: (index: number, key: string, value: any) => { updateTableData: (index: number, key: string, value: any) => {
return getTableInstance().updateTableData(index, key, value); return getTableInstance().updateTableData(index, key, value);
}, },
getRowSelection: () => { getRowSelection: () => {
return getTableInstance().getRowSelection(); return toRaw(getTableInstance().getRowSelection());
}, },
getCacheColumns: () => { getCacheColumns: () => {
return getTableInstance().getCacheColumns(); return toRaw(getTableInstance().getCacheColumns());
}, },
getForm: () => { getForm: () => {
return (unref(formRef) as unknown) as FormActionType; return (unref(formRef) as unknown) as FormActionType;
@@ -129,7 +129,7 @@ export function useTable(
getTableInstance().setShowPagination(show); getTableInstance().setShowPagination(show);
}, },
getShowPagination: () => { getShowPagination: () => {
return getTableInstance().getShowPagination(); return toRaw(getTableInstance().getShowPagination());
}, },
}; };

View File

@@ -75,7 +75,7 @@ export function useTableScroll(
// Table height from bottom height-custom offset // Table height from bottom height-custom offset
const paddingHeight = 32; const paddingHeight = 32;
const borderHeight = 2 * 2; const borderHeight = 0;
// Pager height // Pager height
let paginationHeight = 2; let paginationHeight = 2;
if (!isBoolean(pagination)) { if (!isBoolean(pagination)) {

View File

@@ -49,6 +49,8 @@ export const basicProps = {
default: null, default: null,
}, },
indentSize: propTypes.number.def(24),
canColDrag: propTypes.bool.def(true), canColDrag: propTypes.bool.def(true),
api: { api: {
type: Function as PropType<(...arg: any[]) => Promise<any>>, type: Function as PropType<(...arg: any[]) => Promise<any>>,
@@ -74,7 +76,6 @@ export const basicProps = {
}, },
// 立即请求接口 // 立即请求接口
immediate: propTypes.bool.def(true), immediate: propTypes.bool.def(true),
emptyDataIsShowTable: propTypes.bool.def(true), emptyDataIsShowTable: propTypes.bool.def(true),
// 额外的请求参数 // 额外的请求参数
searchInfo: { searchInfo: {
@@ -130,12 +131,10 @@ export const basicProps = {
type: [Object, Boolean] as PropType<PaginationProps | boolean>, type: [Object, Boolean] as PropType<PaginationProps | boolean>,
default: null, default: null,
}, },
loading: propTypes.bool, loading: propTypes.bool,
rowClassName: { rowClassName: {
type: Function as PropType<(record: TableCustomRecord<any>, index: number) => string>, type: Function as PropType<(record: TableCustomRecord<any>, index: number) => string>,
}, },
scroll: { scroll: {
type: Object as PropType<{ x: number | true; y: number }>, type: Object as PropType<{ x: number | true; y: number }>,
default: null, default: null,

View File

@@ -4,18 +4,19 @@
.@{prefix-cls} { .@{prefix-cls} {
&-form-container { &-form-container {
width: 100%;
padding: 16px; padding: 16px;
.ant-form { .ant-form {
padding: 20px 20px 4px 12px; padding: 16px 16px 6px 12px;
margin-bottom: 18px; margin-bottom: 18px;
background: #fff; background: #fff;
border-radius: 4px; border-radius: 4px;
} }
.ant-table-wrapper { // .ant-table-wrapper {
border-radius: 2px; // border-radius: 2px;
} // }
} }
&-row__striped { &-row__striped {
@@ -37,7 +38,7 @@
.ant-table-wrapper { .ant-table-wrapper {
padding: 8px; padding: 8px;
background: #fff; background: #fff;
border-radius: 4px; border-radius: 2px;
.ant-table-title { .ant-table-title {
padding: 0 0 8px 0 !important; padding: 0 0 8px 0 !important;
@@ -52,7 +53,7 @@
.ant-table { .ant-table {
width: 100%; width: 100%;
overflow-x: hidden; overflow-x: hidden;
border: none; // border: none;
&-title { &-title {
display: flex; display: flex;
@@ -62,50 +63,50 @@
align-items: center; align-items: center;
} }
.ant-table-thead > tr > th, // .ant-table-thead > tr > th,
.ant-table-header { // .ant-table-header {
background: #f1f3f4; // background: #f1f3f4;
background-color: #f1f3f4 !important; // background-color: #f1f3f4 !important;
} // }
.ant-table-tbody > tr.ant-table-row-selected td { .ant-table-tbody > tr.ant-table-row-selected td {
background: fade(@primary-color, 8%) !important; background: fade(@primary-color, 8%) !important;
} }
} }
.ant-table-bordered .ant-table-header > table, // .ant-table-bordered .ant-table-header > table,
.ant-table-bordered .ant-table-body > table, // .ant-table-bordered .ant-table-body > table,
.ant-table-bordered .ant-table-fixed-left table, // .ant-table-bordered .ant-table-fixed-left table,
.ant-table-bordered .ant-table-fixed-right table { // .ant-table-bordered .ant-table-fixed-right table {
border: 1px solid @border-color !important; // border: 1px solid @border-color !important;
} // }
.ant-table-thead { // .ant-table-thead {
tr { // tr {
border: none; // border: none;
} // }
th { // th {
border: none; // border: none;
} // }
} // }
.ant-table-bordered .ant-table-tbody > tr > td { // .ant-table-bordered .ant-table-tbody > tr > td {
border-bottom: 1px solid @border-color !important; // border-bottom: 1px solid @border-color !important;
&:last-child { // &:last-child {
border-right: none !important; // border-right: none !important;
} // }
} // }
.ant-table.ant-table-bordered .ant-table-footer, // .ant-table.ant-table-bordered .ant-table-footer,
.ant-table.ant-table-bordered .ant-table-title { // .ant-table.ant-table-bordered .ant-table-title {
border: 1px solid @border-color !important; // border: 1px solid @border-color !important;
} // }
.ant-table-bordered.ant-table-empty .ant-table-placeholder { // .ant-table-bordered.ant-table-empty .ant-table-placeholder {
border: 1px solid @border-color !important; // border: 1px solid @border-color !important;
} // }
.ant-table-tbody > tr > td, .ant-table-tbody > tr > td,
.ant-table-tbody > tr > th, .ant-table-tbody > tr > th,
@@ -114,61 +115,61 @@
white-space: pre; white-space: pre;
} }
.ant-table-row-cell-last { // .ant-table-row-cell-last {
border-right: none !important; // border-right: none !important;
} // }
.ant-table-bordered .ant-table-thead > tr > th, // .ant-table-bordered .ant-table-thead > tr > th,
.ant-table-bordered .ant-table-tbody > tr > td { // .ant-table-bordered .ant-table-tbody > tr > td {
border-right: 1px solid @border-color !important; // border-right: 1px solid @border-color !important;
} // }
.ant-pagination { .ant-pagination {
margin: 10px 0 0 0; margin: 10px 0 0 0;
} }
.ant-table-body { // .ant-table-body {
overflow-x: auto !important; // overflow-x: auto !important;
overflow-y: scroll !important; // overflow-y: scroll !important;
} // }
.ant-table-header { // .ant-table-header {
margin-bottom: 0 !important; // margin-bottom: 0 !important;
overflow-x: hidden !important; // overflow-x: hidden !important;
overflow-y: scroll !important; // overflow-y: scroll !important;
} // }
.ant-table-fixed-right { // .ant-table-fixed-right {
right: -1px; // right: -1px;
.ant-table-header { // .ant-table-header {
border-left: 1px solid @border-color !important; // border-left: 1px solid @border-color !important;
.ant-table-fixed { // .ant-table-fixed {
border-bottom: none; // border-bottom: none;
.ant-table-thead th { // .ant-table-thead th {
background: rgb(241, 243, 244); // background: rgb(241, 243, 244);
} // }
} // }
} // }
} // }
.ant-table-fixed-left { // .ant-table-fixed-left {
.ant-table-header { // .ant-table-header {
overflow-y: hidden !important; // overflow-y: hidden !important;
} // }
.ant-table-fixed { // .ant-table-fixed {
border-bottom: none; // border-bottom: none;
} // }
} // }
.ant-table-bordered .ant-table-thead > tr:not(:last-child) > th, // .ant-table-bordered .ant-table-thead > tr:not(:last-child) > th,
.ant-table-tbody > tr > td { // .ant-table-tbody > tr > td {
word-break: break-word; // word-break: break-word;
border-color: @border-color !important; // // border-color: @border-color !important;
} // }
.ant-table-footer { .ant-table-footer {
padding: 0; padding: 0;

View File

@@ -26,7 +26,7 @@
import plugins from './plugins'; import plugins from './plugins';
import { getTinymce } from './getTinymce'; import { getTinymce } from './getTinymce';
import { useScript } from '/@/hooks/web/useScript'; import { useScript } from '/@/hooks/web/useScript';
import { snowUuid } from '/@/utils/uuid'; import { buildShortUUID } from '/@/utils/uuid';
import { bindHandlers } from './helper'; import { bindHandlers } from './helper';
import lineHeight from './lineHeight'; import lineHeight from './lineHeight';
import { onMountedOrActivated } from '/@/hooks/core/onMountedOrActivated'; import { onMountedOrActivated } from '/@/hooks/core/onMountedOrActivated';
@@ -45,7 +45,7 @@
emits: ['change', 'update:modelValue'], emits: ['change', 'update:modelValue'],
setup(props, { emit, attrs }) { setup(props, { emit, attrs }) {
const editorRef = ref<any>(null); const editorRef = ref<any>(null);
const tinymceId = ref<string>(snowUuid('tiny-vue')); const tinymceId = ref<string>(buildShortUUID('tiny-vue'));
const elRef = ref<Nullable<HTMLElement>>(null); const elRef = ref<Nullable<HTMLElement>>(null);
const { prefixCls } = useDesign('tinymce-container'); const { prefixCls } = useDesign('tinymce-container');
@@ -104,7 +104,7 @@
} }
); );
onMountedOrActivated(() => { onMountedOrActivated(() => {
tinymceId.value = snowUuid('tiny-vue'); tinymceId.value = buildShortUUID('tiny-vue');
nextTick(() => { nextTick(() => {
init(); init();
}); });

View File

@@ -1,6 +1,5 @@
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent'; import BasicTree from './src/index.vue';
export const BasicTree = createAsyncComponent(() => import('./src/BasicTree'));
export { BasicTree };
export type { ContextMenuItem } from '/@/hooks/web/useContextMenu'; export type { ContextMenuItem } from '/@/hooks/web/useContextMenu';
export * from './src/types'; export * from './src/types';

View File

@@ -1,219 +0,0 @@
import './index.less';
import type { ReplaceFields, TreeItem, Keys, CheckKeys, TreeActionType } from './types';
import { defineComponent, reactive, computed, unref, ref, watchEffect, CSSProperties } from 'vue';
import { Tree } from 'ant-design-vue';
import { DownOutlined } from '@ant-design/icons-vue';
import { useContextMenu, ContextMenuItem } from '/@/hooks/web/useContextMenu';
import { isFunction } from '/@/utils/is';
import { omit } from 'lodash-es';
import { extendSlots } from '/@/utils/helper/tsxHelper';
import { basicProps } from './props';
import { useTree } from './useTree';
import { useExpose } from '/@/hooks/core/useExpose';
import { onMounted } from 'vue';
interface State {
expandedKeys: Keys;
selectedKeys: Keys;
checkedKeys: CheckKeys;
}
const prefixCls = 'basic-tree';
export default defineComponent({
name: 'BasicTree',
props: basicProps,
emits: ['update:expandedKeys', 'update:selectedKeys', 'update:value', 'get'],
setup(props, { attrs, slots, emit }) {
const state = reactive<State>({
expandedKeys: props.expandedKeys || [],
selectedKeys: props.selectedKeys || [],
checkedKeys: props.checkedKeys || [],
});
const treeDataRef = ref<TreeItem[]>([]);
const [createContextMenu] = useContextMenu();
const getReplaceFields = computed(
(): Required<ReplaceFields> => {
const { replaceFields } = props;
return {
children: 'children',
title: 'title',
key: 'key',
...replaceFields,
};
}
);
const getContentStyle = computed(
(): CSSProperties => {
const { actionList } = props;
const width = actionList.length * 18;
return {
width: `calc(100% - ${width}px)`,
};
}
);
const getBindValues = computed(() => {
let propsData = {
blockNode: true,
...attrs,
...props,
expandedKeys: state.expandedKeys,
selectedKeys: state.selectedKeys,
checkedKeys: state.checkedKeys,
replaceFields: unref(getReplaceFields),
'onUpdate:expandedKeys': (v: Keys) => {
state.expandedKeys = v;
emit('update:expandedKeys', v);
},
'onUpdate:selectedKeys': (v: Keys) => {
state.selectedKeys = v;
emit('update:selectedKeys', v);
},
onCheck: (v: CheckKeys) => {
state.checkedKeys = v;
emit('update:value', v);
},
onRightClick: handleRightClick,
};
propsData = omit(propsData, 'treeData');
return propsData;
});
const getTreeData = computed((): TreeItem[] => unref(treeDataRef));
const { deleteNodeByKey, insertNodeByKey, filterByLevel, updateNodeByKey } = useTree(
treeDataRef,
getReplaceFields
);
// 渲染操作按钮
function renderAction(node: TreeItem) {
const { actionList } = props;
if (!actionList || actionList.length === 0) return;
return actionList.map((item, index) => {
return (
<span key={index} class={`${prefixCls}__action`}>
{item.render(node)}
</span>
);
});
}
// 渲染树节点
function renderTreeNode({ data }: { data: TreeItem[] | undefined }) {
if (!data) {
return null;
}
return data.map((item) => {
const { title: titleField, key: keyField, children: childrenField } = unref(
getReplaceFields
);
const propsData = omit(item, 'title');
const anyItem = item as any;
return (
<Tree.TreeNode {...propsData} key={anyItem?.[keyField]}>
{{
title: () => (
<span class={`${prefixCls}-title`}>
<span class={`${prefixCls}__content`} style={unref(getContentStyle)}>
{titleField && anyItem[titleField]}
</span>
<span class={`${prefixCls}__actions`}> {renderAction(item)}</span>
</span>
),
default: () => renderTreeNode({ data: childrenField ? anyItem[childrenField] : [] }),
}}
</Tree.TreeNode>
);
});
}
// 处理右键事件
async function handleRightClick({ event, node }: any) {
const { rightMenuList: menuList = [], beforeRightClick } = props;
let rightMenuList: ContextMenuItem[] = [];
if (beforeRightClick && isFunction(beforeRightClick)) {
rightMenuList = await beforeRightClick(node);
} else {
rightMenuList = menuList;
}
if (!rightMenuList.length) return;
createContextMenu({
event,
items: rightMenuList,
});
}
function setExpandedKeys(keys: string[]) {
state.expandedKeys = keys;
}
function getExpandedKeys() {
return state.expandedKeys;
}
function setSelectedKeys(keys: string[]) {
state.selectedKeys = keys;
}
function getSelectedKeys() {
return state.selectedKeys;
}
function setCheckedKeys(keys: CheckKeys) {
state.checkedKeys = keys;
}
function getCheckedKeys() {
return state.checkedKeys;
}
watchEffect(() => {
treeDataRef.value = props.treeData as TreeItem[];
state.expandedKeys = props.expandedKeys;
state.selectedKeys = props.selectedKeys;
state.checkedKeys = props.checkedKeys;
});
const instance: TreeActionType = {
setExpandedKeys,
getExpandedKeys,
setSelectedKeys,
getSelectedKeys,
setCheckedKeys,
getCheckedKeys,
insertNodeByKey,
deleteNodeByKey,
updateNodeByKey,
filterByLevel: (level: number) => {
state.expandedKeys = filterByLevel(level);
},
};
useExpose<TreeActionType>(instance);
onMounted(() => {
emit('get', instance);
});
return () => {
return (
<Tree {...unref(getBindValues)} class={prefixCls}>
{{
switcherIcon: () => <DownOutlined />,
default: () => renderTreeNode({ data: unref(getTreeData) }),
...extendSlots(slots),
}}
</Tree>
);
};
},
});

View File

@@ -0,0 +1,114 @@
<template>
<div class="flex px-2 py-1.5 items-center border-b-1">
<BasicTitle :helpMessage="helpMessage" v-if="title">{{ title }}</BasicTitle>
<div class="flex flex-1 justify-end items-center cursor-pointer" v-if="search || toolbar">
<div class="mr-1 w-2/3" v-if="search">
<InputSearch :placeholder="t('common.searchText')" size="small" @change="handleSearch" />
</div>
<Dropdown @click.prevent v-if="toolbar">
<Icon icon="ion:ellipsis-vertical" />
<template #overlay>
<Menu @click="handleMenuClick">
<template v-for="item in toolbarList" :key="item.value">
<MenuItem v-bind="{ key: item.value }">
{{ item.label }}
</MenuItem>
<MenuDivider v-if="item.divider" />
</template>
</Menu>
</template>
</Dropdown>
</div>
</div>
</template>
<script lang="ts">
import type { PropType } from 'vue';
import { defineComponent, ref } from 'vue';
import { Dropdown, Menu, Checkbox, Input } from 'ant-design-vue';
import { Icon } from '/@/components/Icon';
import { BasicTitle } from '/@/components/Basic';
import { propTypes } from '/@/utils/propTypes';
import { useI18n } from '/@/hooks/web/useI18n';
import { useDebounce } from '/@/hooks/core/useDebounce';
import { ToolbarEnum } from './enum';
interface MenuInfo {
key: ToolbarEnum;
}
export default defineComponent({
name: 'BasicTreeHeader',
components: {
BasicTitle,
Icon,
Checkbox,
Dropdown,
Menu,
MenuItem: Menu.Item,
MenuDivider: Menu.Divider,
InputSearch: Input.Search,
},
props: {
helpMessage: {
type: [String, Array] as PropType<string | string[]>,
default: '',
},
title: propTypes.string,
toolbar: propTypes.bool,
search: propTypes.bool,
checkAll: propTypes.func,
expandAll: propTypes.func,
},
emits: ['strictly-change', 'search'],
setup(props, { emit }) {
const { t } = useI18n();
const toolbarList = ref([
{ label: t('component.tree.selectAll'), value: ToolbarEnum.SELECT_ALL },
{ label: t('component.tree.unSelectAll'), value: ToolbarEnum.UN_SELECT_ALL, divider: true },
{ label: t('component.tree.expandAll'), value: ToolbarEnum.EXPAND_ALL },
{ label: t('component.tree.unExpandAll'), value: ToolbarEnum.UN_EXPAND_ALL, divider: true },
{ label: t('component.tree.checkStrictly'), value: ToolbarEnum.CHECK_STRICTLY },
{ label: t('component.tree.checkUnStrictly'), value: ToolbarEnum.CHECK_UN_STRICTLY },
]);
function handleMenuClick(e: MenuInfo) {
const { key } = e;
switch (key) {
case ToolbarEnum.SELECT_ALL:
props.checkAll?.(true);
break;
case ToolbarEnum.UN_SELECT_ALL:
props.checkAll?.(false);
break;
case ToolbarEnum.EXPAND_ALL:
props.expandAll?.(true);
break;
case ToolbarEnum.UN_EXPAND_ALL:
props.expandAll?.(false);
break;
case ToolbarEnum.CHECK_STRICTLY:
emit('strictly-change', false);
break;
case ToolbarEnum.CHECK_UN_STRICTLY:
emit('strictly-change', true);
break;
}
}
function emitChange(value?: string): void {
emit('search', value);
}
const [debounceEmitChange] = useDebounce(emitChange, 200);
function handleSearch(e: ChangeEvent): void {
debounceEmitChange(e.target.value);
}
return { t, toolbarList, handleMenuClick, handleSearch };
},
});
</script>

View File

@@ -0,0 +1,17 @@
import type { VNode, FunctionalComponent } from 'vue';
import { h } from 'vue';
import { isString } from '/@/utils/is';
import { Icon } from '/@/components/Icon';
export interface ComponentProps {
icon: VNode | string;
}
export const TreeIcon: FunctionalComponent = ({ icon }: ComponentProps) => {
if (!icon) return null;
if (isString(icon)) {
return h(Icon, { icon, class: 'mr-1' });
}
return Icon;
};

View File

@@ -0,0 +1,8 @@
export enum ToolbarEnum {
SELECT_ALL,
UN_SELECT_ALL,
EXPAND_ALL,
UN_EXPAND_ALL,
CHECK_STRICTLY,
CHECK_UN_STRICTLY,
}

View File

@@ -1,35 +0,0 @@
.basic-tree {
position: relative;
&-title {
position: relative;
display: inline-block;
width: 100%;
padding-right: 10px;
&:hover {
.basic-tree__action {
visibility: visible;
}
}
}
&__content {
display: inline-block;
overflow: hidden;
}
&__actions {
position: absolute;
top: 0;
right: 0;
display: flex;
}
&__action {
margin-left: 4px;
// float: right;
// display: none;
visibility: hidden;
}
}

View File

@@ -0,0 +1,362 @@
<script lang="tsx">
import type { ReplaceFields, Keys, CheckKeys, TreeActionType, TreeItem } from './types';
import { defineComponent, reactive, computed, unref, ref, watchEffect, toRaw, watch } from 'vue';
import { Tree } from 'ant-design-vue';
import { TreeIcon } from './TreeIcon';
import TreeHeader from './TreeHeader.vue';
// import { DownOutlined } from '@ant-design/icons-vue';
import { omit, get } from 'lodash-es';
import { isBoolean, isFunction } from '/@/utils/is';
import { extendSlots } from '/@/utils/helper/tsxHelper';
import { filter } from '/@/utils/helper/treeHelper';
import { useTree } from './useTree';
import { useContextMenu, ContextMenuItem } from '/@/hooks/web/useContextMenu';
import { useExpose } from '/@/hooks/core/useExpose';
import { useDesign } from '/@/hooks/web/useDesign';
import { basicProps } from './props';
interface State {
expandedKeys: Keys;
selectedKeys: Keys;
checkedKeys: CheckKeys;
checkStrictly: boolean;
}
export default defineComponent({
name: 'BasicTree',
inheritAttrs: false,
props: basicProps,
emits: ['update:expandedKeys', 'update:selectedKeys', 'update:value', 'change'],
setup(props, { attrs, slots, emit }) {
const state = reactive<State>({
checkStrictly: props.checkStrictly,
expandedKeys: props.expandedKeys || [],
selectedKeys: props.selectedKeys || [],
checkedKeys: props.checkedKeys || [],
});
const searchState = reactive({
startSearch: false,
searchData: [] as TreeItem[],
});
const treeDataRef = ref<TreeItem[]>([]);
const [createContextMenu] = useContextMenu();
const { prefixCls } = useDesign('basic-tree');
const getReplaceFields = computed(
(): Required<ReplaceFields> => {
const { replaceFields } = props;
return {
children: 'children',
title: 'title',
key: 'key',
...replaceFields,
};
}
);
// const getContentStyle = computed(
// (): CSSProperties => {
// const { actionList } = props;
// const width = actionList.length * 18;
// return {
// width: `calc(100% - ${width}px)`,
// };
// }
// );
const getBindValues = computed(() => {
let propsData = {
blockNode: true,
...attrs,
...props,
expandedKeys: state.expandedKeys,
selectedKeys: state.selectedKeys,
checkedKeys: state.checkedKeys,
checkStrictly: state.checkStrictly,
replaceFields: unref(getReplaceFields),
'onUpdate:expandedKeys': (v: Keys) => {
state.expandedKeys = v;
emit('update:expandedKeys', v);
},
'onUpdate:selectedKeys': (v: Keys) => {
state.selectedKeys = v;
emit('update:selectedKeys', v);
},
onCheck: (v: CheckKeys) => {
state.checkedKeys = v;
const rawVal = toRaw(v);
emit('change', rawVal);
emit('update:value', rawVal);
},
onRightClick: handleRightClick,
};
propsData = omit(propsData, 'treeData', 'class');
return propsData;
});
const getTreeData = computed((): TreeItem[] =>
searchState.startSearch ? searchState.searchData : unref(treeDataRef)
);
const {
deleteNodeByKey,
insertNodeByKey,
filterByLevel,
updateNodeByKey,
getAllKeys,
} = useTree(treeDataRef, getReplaceFields);
function getIcon(params: Recordable, icon?: string) {
if (!icon) {
if (props.renderIcon && isFunction(props.renderIcon)) {
return props.renderIcon(params);
}
}
return icon;
}
async function handleRightClick({ event, node }: any) {
const { rightMenuList: menuList = [], beforeRightClick } = props;
let rightMenuList: ContextMenuItem[] = [];
if (beforeRightClick && isFunction(beforeRightClick)) {
rightMenuList = await beforeRightClick(node);
} else {
rightMenuList = menuList;
}
if (!rightMenuList.length) return;
createContextMenu({
event,
items: rightMenuList,
});
}
function setExpandedKeys(keys: string[]) {
state.expandedKeys = keys;
}
function getExpandedKeys() {
return state.expandedKeys;
}
function setSelectedKeys(keys: string[]) {
state.selectedKeys = keys;
}
function getSelectedKeys() {
return state.selectedKeys;
}
function setCheckedKeys(keys: CheckKeys) {
state.checkedKeys = keys;
}
function getCheckedKeys() {
return state.checkedKeys;
}
function checkAll(checkAll: boolean) {
state.checkedKeys = checkAll ? getAllKeys() : ([] as Keys);
}
function expandAll(expandAll: boolean) {
state.expandedKeys = expandAll ? getAllKeys() : ([] as Keys);
}
function onStrictlyChange(strictly: boolean) {
state.checkStrictly = strictly;
}
function handleSearch(searchValue: string) {
if (!searchValue) {
searchState.startSearch = false;
return;
}
searchState.startSearch = true;
searchState.searchData = filter(unref(treeDataRef), (node) => {
const { title } = node;
return title?.includes(searchValue) ?? false;
// || key?.includes(searchValue);
});
}
watchEffect(() => {
treeDataRef.value = props.treeData as TreeItem[];
state.expandedKeys = props.expandedKeys;
state.selectedKeys = props.selectedKeys;
state.checkedKeys = props.checkedKeys;
});
watch(
() => props.value,
() => {
state.checkedKeys = toRaw(props.value || []);
}
);
// watchEffect(() => {
// console.log('======================');
// console.log(props.value);
// console.log('======================');
// if (props.value) {
// state.checkedKeys = props.value;
// }
// });
watchEffect(() => {
state.checkStrictly = props.checkStrictly;
});
const instance: TreeActionType = {
setExpandedKeys,
getExpandedKeys,
setSelectedKeys,
getSelectedKeys,
setCheckedKeys,
getCheckedKeys,
insertNodeByKey,
deleteNodeByKey,
updateNodeByKey,
checkAll,
expandAll,
filterByLevel: (level: number) => {
state.expandedKeys = filterByLevel(level);
},
};
useExpose<TreeActionType>(instance);
function renderAction(node: TreeItem) {
const { actionList } = props;
if (!actionList || actionList.length === 0) return;
return actionList.map((item, index) => {
if (isFunction(item.show)) {
return item.show?.(node);
}
if (isBoolean(item.show)) {
return item.show;
}
return (
<span key={index} class={`${prefixCls}__action`}>
{item.render(node)}
</span>
);
});
}
function renderTreeNode({ data, level }: { data: TreeItem[] | undefined; level: number }) {
if (!data) {
return null;
}
return data.map((item) => {
const { title: titleField, key: keyField, children: childrenField } = unref(
getReplaceFields
);
const propsData = omit(item, 'title');
const icon = getIcon({ ...item, level }, item.icon);
return (
<Tree.TreeNode {...propsData} node={toRaw(item)} key={get(item, keyField)}>
{{
title: () => (
<span class={`${prefixCls}-title pl-2`}>
{icon && <TreeIcon icon={icon} />}
<span
class={`${prefixCls}__content`}
// style={unref(getContentStyle)}
>
{get(item, titleField)}
</span>
<span class={`${prefixCls}__actions`}> {renderAction({ ...item, level })}</span>
</span>
),
default: () =>
renderTreeNode({ data: get(item, childrenField) || [], level: level + 1 }),
}}
</Tree.TreeNode>
);
});
}
return () => {
const { title, helpMessage, toolbar, search } = props;
return (
<div class={[prefixCls, 'h-full bg-white']}>
{(title || toolbar || search) && (
<TreeHeader
checkAll={checkAll}
expandAll={expandAll}
title={title}
search={search}
toolbar={toolbar}
helpMessage={helpMessage}
onStrictlyChange={onStrictlyChange}
onSearch={handleSearch}
/>
)}
<Tree {...unref(getBindValues)} showIcon={false}>
{{
// switcherIcon: () => <DownOutlined />,
default: () => renderTreeNode({ data: unref(getTreeData), level: 1 }),
...extendSlots(slots),
}}
</Tree>
</div>
);
};
},
});
</script>
<style lang="less">
@prefix-cls: ~'@{namespace}-basic-tree';
.@{prefix-cls} {
.ant-tree-node-content-wrapper {
position: relative;
.ant-tree-title {
position: absolute;
left: 0;
width: 100%;
}
}
&-title {
position: relative;
display: flex;
align-items: center;
width: 100%;
padding-right: 10px;
&:hover {
.@{prefix-cls}__action {
visibility: visible;
}
}
}
&__content {
// display: inline-block;
overflow: hidden;
}
&__actions {
position: absolute;
top: 2px;
right: 3px;
display: flex;
}
&__action {
margin-left: 4px;
visibility: hidden;
}
}
</style>

View File

@@ -1,14 +1,33 @@
import { PropType } from 'vue'; import type { PropType } from 'vue';
import type { ReplaceFields, TreeItem, ActionItem, Keys, CheckKeys } from './types'; import type { ReplaceFields, ActionItem, Keys, CheckKeys } from './types';
import type { ContextMenuItem } from '/@/hooks/web/useContextMenu'; import type { ContextMenuItem } from '/@/hooks/web/useContextMenu';
import type { TreeDataItem } from 'ant-design-vue/es/tree/Tree';
import { propTypes } from '/@/utils/propTypes';
export const basicProps = { export const basicProps = {
value: {
type: Array as PropType<Keys>,
},
renderIcon: {
type: Function as PropType<(params: Recordable) => string>,
},
helpMessage: {
type: [String, Array] as PropType<string | string[]>,
default: '',
},
title: propTypes.string,
toolbar: propTypes.bool,
search: propTypes.bool,
checkStrictly: propTypes.bool,
replaceFields: { replaceFields: {
type: Object as PropType<ReplaceFields>, type: Object as PropType<ReplaceFields>,
}, },
treeData: { treeData: {
type: Array as PropType<TreeItem[]>, type: Array as PropType<TreeDataItem[]>,
}, },
actionList: { actionList: {
@@ -50,7 +69,7 @@ export const treeNodeProps = {
type: Object as PropType<ReplaceFields>, type: Object as PropType<ReplaceFields>,
}, },
treeData: { treeData: {
type: Array as PropType<TreeItem[]>, type: Array as PropType<TreeDataItem[]>,
default: () => [], default: () => [],
}, },
}; };

View File

@@ -1,88 +1,11 @@
import type { TreeDataItem } from 'ant-design-vue/es/tree/Tree';
export interface ActionItem { export interface ActionItem {
render: (record: any) => any; render: (record: Recordable) => any;
show?: boolean | ((record: Recordable) => boolean);
} }
export interface TreeItem { export interface TreeItem extends TreeDataItem {
/**
* Class
* @description className
* @type string
*/
class?: string;
/**
* Style
* @description style of tree node
* @type string | object
*/
style?: string | object;
/**
* Disable Checkbox
* @description Disables the checkbox of the treeNode
* @default false
* @type boolean
*/
disableCheckbox?: boolean;
/**
* Disabled
* @description Disabled or not
* @default false
* @type boolean
*/
disabled?: boolean;
/**
* Icon
* @description customize icon. When you pass component, whose render will receive full TreeNode props as component props
* @type any (slot | slot-scope)
*/
icon?: any; icon?: any;
/**
* Is Leaf?
* @description Leaf node or not
* @default false
* @type boolean
*/
isLeaf?: boolean;
/**
* Key
* @description Required property, should be unique in the tree
* (In tree: Used with (default)ExpandedKeys / (default)CheckedKeys / (default)SelectedKeys)
* @default internal calculated position of treeNode or undefined
* @type string | number
*/
key: string | number;
/**
* Selectable
* @description Set whether the treeNode can be selected
* @default true
* @type boolean
*/
selectable?: boolean;
/**
* Title
* @description Content showed on the treeNodes
* @default '---'
* @type any (string | slot)
*/
title: any;
/**
* Value
* @description Will be treated as treeNodeFilterProp by default, should be unique in the tree
* @default undefined
* @type string
*/
value?: string;
children?: TreeItem[];
slots?: any;
scopedSlots?: any;
} }
export interface ReplaceFields { export interface ReplaceFields {
@@ -98,6 +21,8 @@ export type CheckKeys =
| { checked: string[] | number[]; halfChecked: string[] | number[] }; | { checked: string[] | number[]; halfChecked: string[] | number[] };
export interface TreeActionType { export interface TreeActionType {
checkAll: (checkAll: boolean) => void;
expandAll: (expandAll: boolean) => void;
setExpandedKeys: (keys: Keys) => void; setExpandedKeys: (keys: Keys) => void;
getExpandedKeys: () => Keys; getExpandedKeys: () => Keys;
setSelectedKeys: (keys: Keys) => void; setSelectedKeys: (keys: Keys) => void;
@@ -107,12 +32,12 @@ export interface TreeActionType {
filterByLevel: (level: number) => void; filterByLevel: (level: number) => void;
insertNodeByKey: (opt: InsertNodeParams) => void; insertNodeByKey: (opt: InsertNodeParams) => void;
deleteNodeByKey: (key: string) => void; deleteNodeByKey: (key: string) => void;
updateNodeByKey: (key: string, node: Omit<TreeItem, 'key'>) => void; updateNodeByKey: (key: string, node: Omit<TreeDataItem, 'key'>) => void;
} }
export interface InsertNodeParams { export interface InsertNodeParams {
parentKey: string | null; parentKey: string | null;
node: TreeItem; node: TreeDataItem;
list?: TreeItem[]; list?: TreeDataItem[];
push?: 'push' | 'unshift'; push?: 'push' | 'unshift';
} }

Some files were not shown because too many files have changed in this diff Show More