mirror of
https://github.com/vbenjs/vue-vben-admin.git
synced 2025-08-26 00:26:20 +08:00
Compare commits
141 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
596670dc88 | ||
![]() |
680ad0763c | ||
![]() |
7a7dab0c4b | ||
![]() |
59eb828d4d | ||
![]() |
52af1dd0d4 | ||
![]() |
897bed9729 | ||
![]() |
a764a95ae9 | ||
![]() |
535bdddf91 | ||
![]() |
18567e13a6 | ||
![]() |
03b17a8f8b | ||
![]() |
8832a074dc | ||
![]() |
61ce25be1b | ||
![]() |
d9d0071401 | ||
![]() |
f8440175f3 | ||
![]() |
5baaa58581 | ||
![]() |
f707541dda | ||
![]() |
b06a7ab77b | ||
![]() |
1b3058f825 | ||
![]() |
d81db890df | ||
![]() |
c1178027f0 | ||
![]() |
db7254a5e0 | ||
![]() |
dc51e6a8d4 | ||
![]() |
4b46a84c2b | ||
![]() |
87583c8b54 | ||
![]() |
1e63379088 | ||
![]() |
237e65eac9 | ||
![]() |
6350224a1b | ||
![]() |
ae7821e296 | ||
![]() |
a1d956d369 | ||
![]() |
35e1347029 | ||
![]() |
d95815b503 | ||
![]() |
0a3683a186 | ||
![]() |
f5e31febbd | ||
![]() |
6f830703a2 | ||
![]() |
bfb5ebd7b8 | ||
![]() |
012020e51c | ||
![]() |
aeebfc4d3d | ||
![]() |
c16be2c499 | ||
![]() |
0f28e803d0 | ||
![]() |
cad021c34b | ||
![]() |
5ceeefd17d | ||
![]() |
a9bbed1973 | ||
![]() |
0595a72da9 | ||
![]() |
c7c0a7e4c8 | ||
![]() |
05329ce950 | ||
![]() |
7b76945bff | ||
![]() |
540423ecf7 | ||
![]() |
9cf070dd63 | ||
![]() |
41e6d94b3b | ||
![]() |
17e47e074e | ||
![]() |
dafcdd898c | ||
![]() |
5bce6528ba | ||
![]() |
1e61da644f | ||
![]() |
9228282ae2 | ||
![]() |
45a94e41c1 | ||
![]() |
542121129e | ||
![]() |
cf840e3e73 | ||
![]() |
82eb72bbce | ||
![]() |
5f1a6cdc59 | ||
![]() |
02d3dca57e | ||
![]() |
faf5c9fd7e | ||
![]() |
d5d5c4b4bf | ||
![]() |
993e19dcc3 | ||
![]() |
808291b503 | ||
![]() |
d8c38207c0 | ||
![]() |
f4778431de | ||
![]() |
acacb32bb5 | ||
![]() |
186b274faa | ||
![]() |
f1c0e0c52b | ||
![]() |
735028c430 | ||
![]() |
c8c7615569 | ||
![]() |
c3b907656a | ||
![]() |
b96ea0753b | ||
![]() |
6cbac4b7ec | ||
![]() |
81cf441373 | ||
![]() |
48fcd7684c | ||
![]() |
791b323dbd | ||
![]() |
49f39de7b4 | ||
![]() |
8819af083c | ||
![]() |
73654b7862 | ||
![]() |
5fab267a69 | ||
![]() |
5637588fce | ||
![]() |
5a20df45ad | ||
![]() |
d52b0de83e | ||
![]() |
72ac240f28 | ||
![]() |
b5046f07a2 | ||
![]() |
ddf116da14 | ||
![]() |
5005e6e56b | ||
![]() |
3871204d08 | ||
![]() |
b4a3f936cd | ||
![]() |
16c5d327f1 | ||
![]() |
76a5f87c0c | ||
![]() |
49e72a8e76 | ||
![]() |
6f845b53bd | ||
![]() |
d509e897be | ||
![]() |
424b171e0d | ||
![]() |
9de6ac1119 | ||
![]() |
95c16a5d26 | ||
![]() |
cdb10cc4ac | ||
![]() |
749ba5c1da | ||
![]() |
d38ff6670a | ||
![]() |
e5f37885ff | ||
![]() |
d7b84c7874 | ||
![]() |
c99cf5e53f | ||
![]() |
df0f00085c | ||
![]() |
99829c79ab | ||
![]() |
bdae33e34a | ||
![]() |
e9e51b2fdc | ||
![]() |
1bde404121 | ||
![]() |
c7de65ebba | ||
![]() |
829b366cb2 | ||
![]() |
3dbbde2662 | ||
![]() |
f750ff435f | ||
![]() |
f9cda2e8c0 | ||
![]() |
913c22c84f | ||
![]() |
327d71b8fb | ||
![]() |
941ad59759 | ||
![]() |
d0b6c496d6 | ||
![]() |
20d7a25eb8 | ||
![]() |
59d3e8c80f | ||
![]() |
c73694ab8b | ||
![]() |
81a0f478af | ||
![]() |
d97aa92741 | ||
![]() |
480cfb914e | ||
![]() |
0e414ba3c1 | ||
![]() |
61d4efd55a | ||
![]() |
d5f9919b60 | ||
![]() |
aed622bd09 | ||
![]() |
e78af6f228 | ||
![]() |
4ae39c53b4 | ||
![]() |
fa64fc8a62 | ||
![]() |
a2a75a097f | ||
![]() |
a2d8be3ab2 | ||
![]() |
aec230ca19 | ||
![]() |
a6ef771fcc | ||
![]() |
4d8e39857e | ||
![]() |
c4b22a225d | ||
![]() |
60b80c96e8 | ||
![]() |
9298b3c988 | ||
![]() |
8d22231a5f | ||
![]() |
8eba7fb527 |
36
.env.test
Normal file
36
.env.test
Normal file
@@ -0,0 +1,36 @@
|
||||
NODE_ENV=production
|
||||
# Whether to open mock
|
||||
VITE_USE_MOCK = true
|
||||
|
||||
# public path
|
||||
VITE_PUBLIC_PATH = /
|
||||
|
||||
# Delete console
|
||||
VITE_DROP_CONSOLE = true
|
||||
|
||||
# Whether to enable gzip or brotli compression
|
||||
# Optional: gzip | brotli | none
|
||||
# If you need multiple forms, you can use `,` to separate
|
||||
VITE_BUILD_COMPRESS = 'none'
|
||||
|
||||
# Whether to delete origin files when using compress, default false
|
||||
VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE = false
|
||||
|
||||
# Basic interface address SPA
|
||||
VITE_GLOB_API_URL=/basic-api
|
||||
|
||||
# File upload address, optional
|
||||
# It can be forwarded by nginx or write the actual address directly
|
||||
VITE_GLOB_UPLOAD_URL=/upload
|
||||
|
||||
# Interface prefix
|
||||
VITE_GLOB_API_URL_PREFIX=
|
||||
|
||||
# Whether to enable image compression
|
||||
VITE_USE_IMAGEMIN= true
|
||||
|
||||
# use pwa
|
||||
VITE_USE_PWA = false
|
||||
|
||||
# Is it compatible with older browsers
|
||||
VITE_LEGACY = false
|
@@ -61,6 +61,7 @@ module.exports = defineConfig({
|
||||
'vue/singleline-html-element-content-newline': 'off',
|
||||
'vue/attribute-hyphenation': 'off',
|
||||
'vue/require-default-prop': 'off',
|
||||
'vue/script-setup-uses-vars': 'off',
|
||||
'vue/html-self-closing': [
|
||||
'error',
|
||||
{
|
||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@@ -4,7 +4,8 @@ dist
|
||||
.npmrc
|
||||
.cache
|
||||
|
||||
test/server/static
|
||||
tests/server/static
|
||||
tests/server/static/upload
|
||||
|
||||
.local
|
||||
# local env files
|
||||
|
1
.husky/.gitignore
vendored
1
.husky/.gitignore
vendored
@@ -1 +0,0 @@
|
||||
_
|
20
.vscode/settings.json
vendored
20
.vscode/settings.json
vendored
@@ -129,6 +129,24 @@
|
||||
"qrcode",
|
||||
"sider",
|
||||
"pinia",
|
||||
"sider"
|
||||
"sider",
|
||||
"nprogress",
|
||||
"INTLIFY",
|
||||
"stylelint",
|
||||
"esno",
|
||||
"vitejs",
|
||||
"sortablejs",
|
||||
"mockjs",
|
||||
"codemirror",
|
||||
"iconify",
|
||||
"commitlint",
|
||||
"vditor",
|
||||
"echarts",
|
||||
"cropperjs",
|
||||
"logicflow",
|
||||
"vueuse",
|
||||
"zxcvbn",
|
||||
"lintstagedrc",
|
||||
"brotli"
|
||||
]
|
||||
}
|
||||
|
@@ -1,3 +1,165 @@
|
||||
## 2.6.1(2021-07-19)
|
||||
|
||||
### ✨ Features
|
||||
|
||||
- **NoticeList** Add pagination, auto omit for overlength, title click event, title strikethrough, etc.
|
||||
- **MixSider** Optimize the style of the bottom collapse button in the Mix menu layout to be consistent with the style of other menu layouts
|
||||
- **ApiTreeSelect** Extend `TreeSelect` component of `antdv` to support remote data source, similar to `ApiSelect`.
|
||||
- **BasicTable** New `ApiTreeSelect` editing component
|
||||
- Different backend home pages can be specified for different users.
|
||||
- Add `homePath` field (optional) to the user information returned by the `getUserInfo` interface to customize the home page path for the current user
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- **BasicTable**
|
||||
- Fix scrollbar style issue (removed scroll style patch)
|
||||
- Fix the alignment problem of cells with expanded icons in tree tables
|
||||
- Add `headerTop` slot.
|
||||
- Fix the color display of the operation column button in disabled state.
|
||||
- Repair the problem that the values of editable cells cannot be updated by modifying `dataSource` directly.
|
||||
- Repair the problem of data replay when using `ApiSelect` to edit components.
|
||||
- Repair the problem that editing components may report `onXXX` type error in some scenarios.
|
||||
- **TableAction**
|
||||
- Create Tooltip component only if `action.tooltip` exists.
|
||||
- Fix the problem that the content of the round button inside the component is not centered
|
||||
- **AppSearch** Fix the problem that the hidden menu may be searched.
|
||||
- **BasicUpload** Repair the problem of error when handling non-`array` values.
|
||||
- **Form** Repair the `suffix` slot style problem of `FormItem`.
|
||||
- **Menu**
|
||||
- Repair the hovering trigger logic of the left mixed menu
|
||||
- Repair the problem that the top bar menu is wrong when displaying menu items that need to be hidden.
|
||||
- Fix the left mixed menu in hover trigger mode will jump to route directly when there is no submenu and it is activated
|
||||
- **Breadcrumb** Repair the problem that the menu with redirection cannot be jumped when clicked
|
||||
- **Markdown** fixes an initialization exception and an issue where value was not set dynamically correctly
|
||||
- **Modal** Make sure props are passed correctly
|
||||
- **MultipleTab** fixes an issue that could accidentally create login route tabs
|
||||
- **BasicTree** Fix the problem that the search function may cause `checkedKeys` to be lost
|
||||
- **CodeEditor** Fix the problem that value does not support v-model usage.
|
||||
- **CountdownInput** Fix the problem that `input` slot is not supported.
|
||||
- **ApiSelect** Fix the problem that the `options-change` event parameter is not the standard `options` data used by `select
|
||||
- **Other**
|
||||
- Fix the problem that the configuration of default menu collapse does not work
|
||||
- Repair the problem that `safari` browser reports an error and the website cannot be opened.
|
||||
- Repair the problem that eslint keeps error due to endOfLine after pulling the code on window.
|
||||
- Fix `Vue Router warn` caused by dynamic routing
|
||||
|
||||
### 🎫 Chores
|
||||
|
||||
- Add test environment test command
|
||||
|
||||
## 2.6.0(2021-07-04)
|
||||
|
||||
### ✨ Features
|
||||
|
||||
- **Axios** New `withToken` configuration to control whether the request carries a token or not
|
||||
- **BasicUpload**
|
||||
- New `preview-delete` event triggered when deleting a file in preview `Modal`.
|
||||
- `value` supports `v-model` usage
|
||||
- **Route configuration**
|
||||
- Add `ignoreRoute` to generate menu only in `ROUTE_MAPPING` or `BACK` permission mode
|
||||
- Add `hidePathForChildren` configuration to ignore this level `path` when generating menus for child items
|
||||
- **TableAction** Add `tooltip` configuration to add tooltip hint for button
|
||||
- **CropperAvatar**
|
||||
- Added `value` to set the current avatar
|
||||
- Added `onChange` to accept avatar cropping and upload success event
|
||||
- New `btnText`, `btnProps` for customizing the text and properties of the upload button
|
||||
- Add tooltips to the action buttons in `Modal` for cropping
|
||||
- **Modal** Add tooltip for action button in top right corner
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- **Modal**
|
||||
- Fix the problem that the mask cannot be closed by clicking on it.
|
||||
- Fix `setModalProps` does not support setting `defaultFullscreen`.
|
||||
- **Table**
|
||||
- Fix the problem that `editComponentProps` doesn't support `onChange`.
|
||||
- Fix the problem that `selection-change` event is not triggered when `clickToRowSelect` is enabled.
|
||||
- Fix the problem that global configuration `fetchSetting` may be accidentally modified by local configuration.
|
||||
- Fix the problem that the parameter of `handleSearchInfoFn` contains redundant blank keys.
|
||||
- Repair the problem that when rowSelection.onChange is provided for table, the selected items of table cannot be changed manually.
|
||||
- Fix the problem that the scrollbar continues to be displayed even when it is not needed to be displayed.
|
||||
- **Icon** Repair the problem that SvgIcon is missing some styles.
|
||||
- **Menu**
|
||||
- Repair the problem that single-level menu refreshing will not be activated in route mapping mode.
|
||||
- Repair the problem that the collapse customization at the bottom of the side menu is invalid.
|
||||
- **Form** Repair the type definition of `submitButtonOptions` and `resetButtonOptions`.
|
||||
- **PopConfirmButton** Remove the redundant `title` on `Button`.
|
||||
- **Axios** Fix the problem that `params` and `data` data cannot be submitted at the same time when non-`GET` requests are made
|
||||
- **Other**
|
||||
- Repair the problem that the lock screen function can skip the lock state by refreshing the page or copying the URL to open a new browser tab
|
||||
- Repair the problem that `Token` won't be synchronized when multiple windows open pages at the same time.
|
||||
- Repair the problem that `hasPermission` does not work in `ROLE` permission mode.
|
||||
- **Table** Repair the problem that the parameter of `handleSearchInfoFn` contains extra blank keys.
|
||||
- **Tailwindcss** Remove console warning
|
||||
|
||||
## 2.5.2(2021-06-27)
|
||||
|
||||
### ⚡ Performance Improvements
|
||||
|
||||
- **Icon** Remove the global registration of Icon components to prevent hot update issues under certain circumstances
|
||||
|
||||
### ✨ Features
|
||||
|
||||
- **Menu** Added `permissionMode=PermissionModeEnum.ROUTE_MAPPING` mode
|
||||
- The project is changed to this mode by default, and the original menu file is deleted
|
||||
- If you have written the menu before, you can change to `PermissionModeEnum.ROLE` mode
|
||||
|
||||
## 2.5.1(2021-06-26)
|
||||
|
||||
### ⚡ Performance Improvements
|
||||
|
||||
- Upgrade `vue` and `ant-design-vue` versions to solve compatibility issues
|
||||
- **Tree** Performance optimization
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- **Table** Fix page jitter problem
|
||||
- **Upload** Make sure to carry custom parameters
|
||||
- **Dropdown** Fix the icon display problem of popConfirm
|
||||
- **Table** Fix the problem that the editing event of the tree table is abnormal
|
||||
- **Table** Fix the problem that when the table data is empty, the value returned by getDataSource is not the data source used by the table
|
||||
|
||||
## 2.5.0(2021-06-20)
|
||||
|
||||
## (Breaking changes) Breaking changes
|
||||
|
||||
- Change the project `windicss` to `tailwindcss` to solve the memory overflow problem
|
||||
- There are currently incompatible areas of the project
|
||||
- The wording of `!xl:m-4` needs to be changed to `xl:!m-4`, note that only `!` is incompatible. If you don’t use it, you don’t need to change it.
|
||||
- The new features of `windicss` itself need to be adjusted, for example, `Attribute` mode is not compatible
|
||||
|
||||
### ✨ Refactor
|
||||
|
||||
- Remove `useExpose` and use `expose` provided by the component itself instead
|
||||
|
||||
### ⚡ Performance Improvements
|
||||
|
||||
- **Locale** merge multi-language files to reduce the number of files
|
||||
- **Utils** Mitt default export is changed from `Class` to `Function`
|
||||
- **Axios** `isTransformRequestResult` is renamed to `isTransformResponse`
|
||||
|
||||
### ✨ Features
|
||||
|
||||
- **CropperImage** `Cropper` Avatar cropping adds circular cropping function
|
||||
- **CropperAvatar** Added avatar upload component
|
||||
- **Drawer** `useDrawer` added `closeDrawer` function
|
||||
- **Preview** Added `createImgPreview` picture preview function
|
||||
- **Setup** New guide page example
|
||||
- **Tests** Add jest test suite, Vue component single test is not currently supported
|
||||
- **Axios** Added `authenticationScheme` configuration to specify the authentication scheme
|
||||
- **Setting** Added `sessionTimeoutProcessing` project configuration item, used to configure how to deal with session timeout
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- **Modal** fix full screen height calculation error
|
||||
- **Modal** Fix the problem that the shutdown event is triggered multiple times
|
||||
- **PageWrapper** fix the height calculation problem
|
||||
- **FlowChart** Repair drag and drop menu missing
|
||||
- Fixed Iframe routing error in background mode
|
||||
- **PageWrapper** Fix the height calculation problem when footer and global footer are opened at the same time
|
||||
- **Menu** Fix the jitter problem of menu folding animation
|
||||
- **Store** fixed type error after pinia version upgrade
|
||||
|
||||
## 2.4.2(2021-06-10)
|
||||
|
||||
### ✨ Refactor
|
||||
|
370
CHANGELOG.md
370
CHANGELOG.md
@@ -1,3 +1,373 @@
|
||||
## [2.6.1](https://github.com/anncwb/vue-vben-admin/compare/v2.6.0...v2.6.1) (2021-07-19)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **api-select:** fix `options-change` event data ([897bed9](https://github.com/anncwb/vue-vben-admin/commit/897bed97295a0b9101d33102340749689a4368de))
|
||||
- **api-tree-select:** auto load data if necessary ([1b3058f](https://github.com/anncwb/vue-vben-admin/commit/1b3058f8253effe974feaf08a12250a111ab58c0))
|
||||
- **api-tree-select:** fix `event` checked in form ([d9d0071](https://github.com/anncwb/vue-vben-admin/commit/d9d00714011fa7914c61f990ce1159351ee21a1a))
|
||||
- **app-search:** exclude hidden items ([faf5c9f](https://github.com/anncwb/vue-vben-admin/commit/faf5c9fd7ea40c407419a5a5c473f9b0c32c2a53))
|
||||
- **app-search:** exclude items by `hideChildrenInMenu` ([02d3dca](https://github.com/anncwb/vue-vben-admin/commit/02d3dca57efedc1322ae38e3f432cf1f6c2cf839))
|
||||
- **basic-tree:** `checkedKeys` not worked with `search` ([b06a7ab](https://github.com/anncwb/vue-vben-admin/commit/b06a7ab77b99abee63dd55770ffd55b594ee42f9)), closes [#915](https://github.com/anncwb/vue-vben-admin/issues/915)
|
||||
- **breadcrumb:** `redirect` not worked ([f5e31fe](https://github.com/anncwb/vue-vben-admin/commit/f5e31febbd18372a34166cac390b1d9b914fe80e))
|
||||
- **code-editor:** `value` not support use as `v-model` ([8832a07](https://github.com/anncwb/vue-vben-admin/commit/8832a074dceb44f057c87289d3a99feef58c08fd)), closes [#933](https://github.com/anncwb/vue-vben-admin/issues/933)
|
||||
- **countdown-input:** add `slots` support ([a764a95](https://github.com/anncwb/vue-vben-admin/commit/a764a95ae9a6cff831f75aa97b00724cadc48e92))
|
||||
- **CountTo:** Fix displaying empty string when the value is 0 ([#864](https://github.com/anncwb/vue-vben-admin/issues/864)) ([82eb72b](https://github.com/anncwb/vue-vben-admin/commit/82eb72bbced931ba7f50069211f9511035ad09f4))
|
||||
- **demo:** `setup` page route config ([d5d5c4b](https://github.com/anncwb/vue-vben-admin/commit/d5d5c4b4bfb3e3a5e54f9993966adc46a09a8b90))
|
||||
- **demo:** add mock data `account detail` route ([993e19d](https://github.com/anncwb/vue-vben-admin/commit/993e19dcc319e2b4c68df2ab76174b7b4d7b0428)), closes [#858](https://github.com/anncwb/vue-vben-admin/issues/858)
|
||||
- **demo:** fix display problem of editable table with `apiSelect` ([535bddd](https://github.com/anncwb/vue-vben-admin/commit/535bdddf91785e20295c18cf80c8a22cc2172681))
|
||||
- **demo:** form pages support `keepAlive` ([9228282](https://github.com/anncwb/vue-vben-admin/commit/9228282ae27daaa246f42e441e27b1b05eb30464))
|
||||
- **demo:** resolve `key not exist` warnings ([45a94e4](https://github.com/anncwb/vue-vben-admin/commit/45a94e41c1397b84d08373f84f766204d2488714))
|
||||
- **form:** fix `suffix` slot style ([a9bbed1](https://github.com/anncwb/vue-vben-admin/commit/a9bbed19739376ab2bf67a14b04e872f14ca84cc))
|
||||
- **formItem:** Fix labelcol type mismatch ([#903](https://github.com/anncwb/vue-vben-admin/issues/903)) ([03b17a8](https://github.com/anncwb/vue-vben-admin/commit/03b17a8f8bdb50322aa10e3b614bcc40b9e9dcc8))
|
||||
- **markdown:** resolving markdown exceptions ([d95815b](https://github.com/anncwb/vue-vben-admin/commit/d95815b5031984e224140eb1b1d46e2dbf80abc1))
|
||||
- **markdown:** set `value` error ([35e1347](https://github.com/anncwb/vue-vben-admin/commit/35e1347029e29a83a9648b6b398e6863cc40fca9))
|
||||
- **menu:** display error when contains hidden items ([5ceeefd](https://github.com/anncwb/vue-vben-admin/commit/5ceeefd17d9ddc0e8844b900069b100f24d9c00e))
|
||||
- **menu:** fix mix-menu incorrect jumping in `hover` mode ([cad021c](https://github.com/anncwb/vue-vben-admin/commit/cad021c34b71fa109640af75a0c2b72179e9e257))
|
||||
- **mix-sider:** fix mix-sider hover logic ([0595a72](https://github.com/anncwb/vue-vben-admin/commit/0595a72da9c666af81a0916663e8e6a014e6fa69))
|
||||
- **modal:** ensure that props are passed correctly,fix [#897](https://github.com/anncwb/vue-vben-admin/issues/897) ([ae7821e](https://github.com/anncwb/vue-vben-admin/commit/ae7821e29690bea8934ea724bfd0ae4e2cf30c77))
|
||||
- **modal:** fixed `fullscreen` not worked ([5baaa58](https://github.com/anncwb/vue-vben-admin/commit/5baaa58581f22a915cda9fa39e4cb9f094254d3b)), closes [#918](https://github.com/anncwb/vue-vben-admin/issues/918)
|
||||
- **model:** auto validate on value change ([f844017](https://github.com/anncwb/vue-vben-admin/commit/f8440175f35076073c9f53483cf6c0164d427ff4)), closes [#920](https://github.com/anncwb/vue-vben-admin/issues/920)
|
||||
- **table:** fix index column style ([c7c0a7e](https://github.com/anncwb/vue-vben-admin/commit/c7c0a7e4c88a895000b1621981e4d4b2020c64b1))
|
||||
- **table:** `value` show problem in editable cell ([61ce25b](https://github.com/anncwb/vue-vben-admin/commit/61ce25be1b40d7a0e26205ca6a6757c6c43fc21e)), closes [#922](https://github.com/anncwb/vue-vben-admin/issues/922)
|
||||
- **table-action:** fixed icon `margin` without label ([dc51e6a](https://github.com/anncwb/vue-vben-admin/commit/dc51e6a8d4e4f2c97b387b37959944c9bb49d779))
|
||||
- **tree:** fixed `checkedKeys` with `search` mode ([f707541](https://github.com/anncwb/vue-vben-admin/commit/f707541dda78146bda89814ddccbb259d9f5d8a2))
|
||||
- fix homePage affix error ([c117802](https://github.com/anncwb/vue-vben-admin/commit/c1178027f0fab2791d02efcd7c52beff5fc7dc25))
|
||||
- **table-action:** fix `circle` button style ([db7254a](https://github.com/anncwb/vue-vben-admin/commit/db7254a5e0ac6d10a7ea37334ad523b150facb19))
|
||||
- `menuSetting` can not set collapsed to false as default ([808291b](https://github.com/anncwb/vue-vben-admin/commit/808291b503d59e3026f5f0b5e7a38b9c69bcc451))
|
||||
- ensure PAGE_NOT_FOUND_ROUTE exist ([87583c8](https://github.com/anncwb/vue-vben-admin/commit/87583c8b54d335ddf1c416859ef62bbde189c809))
|
||||
- ensure that safari is running properly, fix [#875](https://github.com/anncwb/vue-vben-admin/issues/875) ([dafcdd8](https://github.com/anncwb/vue-vben-admin/commit/dafcdd898caae57104f1155b0ec660ea333e7b19))
|
||||
- infinite redirect in `BACK` mode ([4b46a84](https://github.com/anncwb/vue-vben-admin/commit/4b46a84c2b85e8da799426c54b3381ae93183db4))
|
||||
- **multiple-tab:** ignore login page ([1e63379](https://github.com/anncwb/vue-vben-admin/commit/1e63379088e1d7c823f29f607ab49d62ca22cb25))
|
||||
- resolving `Vue Router warn` ([237e65e](https://github.com/anncwb/vue-vben-admin/commit/237e65eac909368c4b4857da6c8deb1dc18e7684))
|
||||
- **table:** fix tree node align ([1e61da6](https://github.com/anncwb/vue-vben-admin/commit/1e61da644f65a79ce10fde98ee017aba7d36be10)), closes [#829](https://github.com/anncwb/vue-vben-admin/issues/829)
|
||||
- **table:** scrollbar style ([d8c3820](https://github.com/anncwb/vue-vben-admin/commit/d8c38207c08510d805a8dc66ffbba210e0cf4215))
|
||||
- **table-action:** incorrect button color of `disabled` state ([0f28e80](https://github.com/anncwb/vue-vben-admin/commit/0f28e803d0b65537216cd9f40ad5cad63c20db9b)), closes [#891](https://github.com/anncwb/vue-vben-admin/issues/891)
|
||||
- **upload:** ensure the value type is correct ([05329ce](https://github.com/anncwb/vue-vben-admin/commit/05329ce9501eb899a0bbb45320e5807c83372317))
|
||||
- **useWatermark:** fix `func` call `createWatermark` call `clear` to resizeEvent removed ([#901](https://github.com/anncwb/vue-vben-admin/issues/901)) ([a1d956d](https://github.com/anncwb/vue-vben-admin/commit/a1d956d3697cd07e0ba8910768f2a73e55f18491))
|
||||
|
||||
### Features
|
||||
|
||||
- **api-tree-select:** add `api` options to tree-select ([d81db89](https://github.com/anncwb/vue-vben-admin/commit/d81db890dfeb533d60f378ddb86f8ac50a31252b))
|
||||
- **basic-table:** add `ApiTreeSelect` edit component ([52af1dd](https://github.com/anncwb/vue-vben-admin/commit/52af1dd0d494e66c0af20f886dcc2b983cbb096f))
|
||||
- **demo:** multi-modal in one page usage ([7a7dab0](https://github.com/anncwb/vue-vben-admin/commit/7a7dab0c4b3602b7bd3e9381408e4168d7494c52))
|
||||
- customized user home page ([0a3683a](https://github.com/anncwb/vue-vben-admin/commit/0a3683a186ab55d34a12a5a3c6d794dfa1094ad4))
|
||||
- **api-select:** clear options before fetch ([9cf070d](https://github.com/anncwb/vue-vben-admin/commit/9cf070dd6305bb69a67ab6be85ef00bddc86fda0))
|
||||
- **demo:** add basicTree with async data expand all ([5421211](https://github.com/anncwb/vue-vben-admin/commit/542121129eb5bf65f61e7b484835591756c80f04))
|
||||
- **demo:** add search demo for apiSelect ([41e6d94](https://github.com/anncwb/vue-vben-admin/commit/41e6d94b3b64dc0d40b7ec57ecfaa4d966f202ae))
|
||||
- **demo:** demo default expanded tree table ([5f1a6cd](https://github.com/anncwb/vue-vben-admin/commit/5f1a6cdc599d5840df2dfebdaad029aac093cd81))
|
||||
- **notice-list:** add `pagination` support ([c16be2c](https://github.com/anncwb/vue-vben-admin/commit/c16be2c499d90126dfa35d699da9294c21a4ab48)), closes [#894](https://github.com/anncwb/vue-vben-admin/issues/894)
|
||||
- **table:** add `headerTop` slot ([540423e](https://github.com/anncwb/vue-vben-admin/commit/540423ecf741a815d28d7a6baa1541ac884efe95)), closes [#881](https://github.com/anncwb/vue-vben-admin/issues/881)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
- **menu:** Optimize the style of the bottom collapse button in the Mix menu layout ([#896](https://github.com/anncwb/vue-vben-admin/issues/896)) ([6f83070](https://github.com/anncwb/vue-vben-admin/commit/6f830703a2607c33e5d25d6d17d0e453fc2fac2e))
|
||||
- image compression configuration optimization ([cf840e3](https://github.com/anncwb/vue-vben-admin/commit/cf840e3e73b9572de0ba7bf7b32d83f6a353a8ad))
|
||||
|
||||
# [2.6.0](https://github.com/anncwb/vue-vben-admin/compare/v2.5.2...v2.6.0) (2021-07-04)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **axios:** option `withToken` not work ([d509e89](https://github.com/anncwb/vue-vben-admin/commit/d509e897be5753c852e912112e70dac6247ba467))
|
||||
- **demo:** account list fetch loss param ([424b171](https://github.com/anncwb/vue-vben-admin/commit/424b171e0db727f5e0157cbcfd5460f15f8ea609)), closes [#830](https://github.com/anncwb/vue-vben-admin/issues/830)
|
||||
- **demo:** fix async tree demo, fixed: [#823](https://github.com/anncwb/vue-vben-admin/issues/823) ([5637588](https://github.com/anncwb/vue-vben-admin/commit/5637588fce880b01137191cc82c73e0fce621e8c))
|
||||
- **form:** fix some prop declaration ([b5046f0](https://github.com/anncwb/vue-vben-admin/commit/b5046f07a27e8ca7fc8b961b74fa5e1b0d715149))
|
||||
- **lock-screen:** ensure lock info is saved ([d38ff66](https://github.com/anncwb/vue-vben-admin/commit/d38ff6670a37478b31447f8058e786c4b044e218))
|
||||
- **lock-screen:** fix lock-screen can skip on new window ([d7b84c7](https://github.com/anncwb/vue-vben-admin/commit/d7b84c78744f7d0077a779b232e1358040b50383))
|
||||
- **menu:** make sure the menu is activated correctly ([cdb10cc](https://github.com/anncwb/vue-vben-admin/commit/cdb10cc4ac5e5e8f9cce3ff18d8fbd29ef10c86f))
|
||||
- **modal:** `setModalProps` support `defaultFullscreen` ([c7de65e](https://github.com/anncwb/vue-vben-admin/commit/c7de65ebba53941771153f18b184d3d4d31c0dbf))
|
||||
- **modal:** maskClosable not work ([f750ff4](https://github.com/anncwb/vue-vben-admin/commit/f750ff435fee06acee78d6b9633e6e18d91685f8))
|
||||
- **modal:** remove console log ([3dbbde2](https://github.com/anncwb/vue-vben-admin/commit/3dbbde2662352780377a9b216598d9348522f6ba))
|
||||
- **popconfirm-button:** remove button excess `title` ([73654b7](https://github.com/anncwb/vue-vben-admin/commit/73654b7862c59d623d6d5dc7dcf6ff2704564d9a))
|
||||
- **sider:** bottom trigger not work ([1bde404](https://github.com/anncwb/vue-vben-admin/commit/1bde4041211229d5d9d01ce0ca806fa99356b6de)), closes [#820](https://github.com/anncwb/vue-vben-admin/issues/820)
|
||||
- **sider:** custom trigger does not take effect ([5005e6e](https://github.com/anncwb/vue-vben-admin/commit/5005e6e56b1cc7763a1cc23e1162dfb49452013b))
|
||||
- **svg-icon:** fix SvgIcon style ([99829c7](https://github.com/anncwb/vue-vben-admin/commit/99829c79ab41a2319f40c5595a7d82d9e406ba18))
|
||||
- **table:** auto hide unnecessary scrollbar ([735028c](https://github.com/anncwb/vue-vben-admin/commit/735028c43055e8e80ebc7344af0cd0f51c744f98))
|
||||
- **table:** global configuration accidentally modified ([b4a3f93](https://github.com/anncwb/vue-vben-admin/commit/b4a3f936cd19bf1fff3a331bacad60e79d2d6c22))
|
||||
- **table:** param of `handleSearchInfoFn` ([791b323](https://github.com/anncwb/vue-vben-admin/commit/791b323dbd30acd7fabfe9c3fb6e528916311ffd))
|
||||
- **tailwindcss:** remove console warnings ([acacb32](https://github.com/anncwb/vue-vben-admin/commit/acacb32bb592345cd0a90b4bbeb60a9b6ab1ac3c))
|
||||
- `hasPermission` not work in `ROLE` Mode ([76a5f87](https://github.com/anncwb/vue-vben-admin/commit/76a5f87c0ce871cca48b9e4c32331353a796e7d2))
|
||||
- routes filter can't effective when permission mode set to ROUTE_MAPPING ([#836](https://github.com/anncwb/vue-vben-admin/issues/836)) ([3871204](https://github.com/anncwb/vue-vben-admin/commit/3871204d08d481b8984440cd60bbf2bacb58d063))
|
||||
- **table:** selection-change not triggered on row click ([6f845b5](https://github.com/anncwb/vue-vben-admin/commit/6f845b53bdc4c33fbca3e65f10f64c63166bed0e))
|
||||
- multi windows token sharing ([e5f3788](https://github.com/anncwb/vue-vben-admin/commit/e5f37885ffb32d04d244f0ef39ac660dda6b71e1)), closes [#761](https://github.com/anncwb/vue-vben-admin/issues/761)
|
||||
- support various vite modes of build, not just production ([#832](https://github.com/anncwb/vue-vben-admin/issues/832)) ([95c16a5](https://github.com/anncwb/vue-vben-admin/commit/95c16a5d26f9fd9a1d11894afe1146ca495eee93))
|
||||
- **table:** editComponentProps support onChange ([829b366](https://github.com/anncwb/vue-vben-admin/commit/829b366cb2abf27e69d9665e5be022b3d3f15655))
|
||||
- **table:** fix rowSelection.onChange not work ([df0f000](https://github.com/anncwb/vue-vben-admin/commit/df0f00085c1113eddd7a15954818ccece3538068)), closes [#825](https://github.com/anncwb/vue-vben-admin/issues/825)
|
||||
|
||||
### Features
|
||||
|
||||
- **avatar-cropper:** add action tooltip ([6cbac4b](https://github.com/anncwb/vue-vben-admin/commit/6cbac4b7ece60a1a7c1fda931cfffce42dfe3e51))
|
||||
- **avatar-cropper:** more props added ([b96ea07](https://github.com/anncwb/vue-vben-admin/commit/b96ea0753bfd769693a368cf1e3d8316688c0dcb))
|
||||
- **axios:** add `withToken` option ([c99cf5e](https://github.com/anncwb/vue-vben-admin/commit/c99cf5e53f057cdc332ab6c0635adf9c2d27de29))
|
||||
- **axios:** use `defHttp` like `axios` ([49f39de](https://github.com/anncwb/vue-vben-admin/commit/49f39de7b40e3ec8343bdeaf3eb00fd79d395746)), closes [#850](https://github.com/anncwb/vue-vben-admin/issues/850)
|
||||
- **basic-upload:** `value` support v-model ([16c5d32](https://github.com/anncwb/vue-vben-admin/commit/16c5d327f1209f7c7437acde2ab0fa031da6a641))
|
||||
- **basic-upload:** add preview-delete event ([49e72a8](https://github.com/anncwb/vue-vben-admin/commit/49e72a8e76b78fe54e19de9e23d7c72a19427f01)), closes [#835](https://github.com/anncwb/vue-vben-admin/issues/835)
|
||||
- **modal:** add `tooltip` for action buttons ([c3b9076](https://github.com/anncwb/vue-vben-admin/commit/c3b907656a5fad7a9b241562179f7a0f6fe0e6f0))
|
||||
- **param-menu:** feature: menu with params ([#845](https://github.com/anncwb/vue-vben-admin/issues/845)) ([48fcd76](https://github.com/anncwb/vue-vben-admin/commit/48fcd7684cabff66e8648b71527c6cb4ce7d03be))
|
||||
- **route:** add `hidePathForChildren` in `meta` ([d52b0de](https://github.com/anncwb/vue-vben-admin/commit/d52b0de83e69f7505c28e6f59ec84bbe526ecd0d))
|
||||
- **table:** support asynchrony in beforeFetch and afterFetch ([#827](https://github.com/anncwb/vue-vben-admin/issues/827)) ([749ba5c](https://github.com/anncwb/vue-vben-admin/commit/749ba5c1daf459625518937c239787b756c0a780))
|
||||
- **table-action:** support `tooltip` option ([5fab267](https://github.com/anncwb/vue-vben-admin/commit/5fab267a69600fdf5d7a7f9e4d9fff859d09dede)), closes [#848](https://github.com/anncwb/vue-vben-admin/issues/848)
|
||||
- **tree:** add `insertNodesByKey` method ([5a20df4](https://github.com/anncwb/vue-vben-admin/commit/5a20df45ad36b523d48bf7fe11bdb10a6d03df64))
|
||||
- routers support `ignoreRoute` option ([72ac240](https://github.com/anncwb/vue-vben-admin/commit/72ac240f2858cd74cb62b7647ca89d63bb71d247))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
- **scrollbar:** scrollbar update when slot changed ([e9e51b2](https://github.com/anncwb/vue-vben-admin/commit/e9e51b2fdc879a66d8df08504a0955c9c21e3e27))
|
||||
|
||||
## [2.5.1](https://github.com/anncwb/vue-vben-admin/compare/v2.4.0...v2.5.1) (2021-06-26)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **comp-tree:** support comp-tree-foreach stop,add insertNodesByKey ([#818](https://github.com/anncwb/vue-vben-admin/issues/818)) ([d97aa92](https://github.com/anncwb/vue-vben-admin/commit/d97aa927417bf45a7c127ecfa9b8e835b6b68855))
|
||||
- fix antdv console warning ([480cfb9](https://github.com/anncwb/vue-vben-admin/commit/480cfb914e78c06eb7784e33465ed91b7d4c3eee))
|
||||
- fix defHttp baseUrl work ([d5f9919](https://github.com/anncwb/vue-vben-admin/commit/d5f9919b60fdd7d5c435129e8db519c0bbd37529))
|
||||
- **api:** select api type error ([b387681](https://github.com/anncwb/vue-vben-admin/commit/b387681c00ac018f5bc6a9251009ddffe37acae6))
|
||||
- **api-select:** ensure that the onchange function parameters are correct ([fa64fc8](https://github.com/anncwb/vue-vben-admin/commit/fa64fc8a622832b87fdf672965d55d543b5929a2))
|
||||
- **api-select:** loss option data on event callback ([c5f2577](https://github.com/anncwb/vue-vben-admin/commit/c5f2577f515e7ae96b27b509e5dd4b3317fcb7b4)), closes [#733](https://github.com/anncwb/vue-vben-admin/issues/733)
|
||||
- **ApiSelect demo:** add demo about ApiSelect's use ([#757](https://github.com/anncwb/vue-vben-admin/issues/757)) ([a03d3cc](https://github.com/anncwb/vue-vben-admin/commit/a03d3cc60c770eba644c1f3837850a2c1c015029))
|
||||
- **demo:** `breadcrumb` route invalid redirect ([84d9300](https://github.com/anncwb/vue-vben-admin/commit/84d9300e52fa73da575591aa4b71858a7e459c8c))
|
||||
- **demo:** account list page validate and save ([21f7a85](https://github.com/anncwb/vue-vben-admin/commit/21f7a854fe2455315287d04e895661ff739bce17))
|
||||
- **demo:** make sure the map https resource is correct ([7b9cd09](https://github.com/anncwb/vue-vben-admin/commit/7b9cd09ad8a50c45b2e661e07953d786d82f367d))
|
||||
- **demo:** style error,fix [#806](https://github.com/anncwb/vue-vben-admin/issues/806) ([a2d8be3](https://github.com/anncwb/vue-vben-admin/commit/a2d8be3ab29da88126f3ba971f6893cb12327759))
|
||||
- **demo-form:** add fieldMapToTime example,fix [#807](https://github.com/anncwb/vue-vben-admin/issues/807) ([a2a75a0](https://github.com/anncwb/vue-vben-admin/commit/a2a75a097ff6c9df12471eff0d62d44d2b88cfff))
|
||||
- **design:** correct tailwind configuration,fix [#800](https://github.com/anncwb/vue-vben-admin/issues/800) ([aec230c](https://github.com/anncwb/vue-vben-admin/commit/aec230ca19d541079b64c54ba00596ef9cd92ca0))
|
||||
- **dropdown:** icon and trigger work unexpected ([60b80c9](https://github.com/anncwb/vue-vben-admin/commit/60b80c96e82da9101d56b2e195e9e7571de11f0a)), closes [#796](https://github.com/anncwb/vue-vben-admin/issues/796) [#787](https://github.com/anncwb/vue-vben-admin/issues/787)
|
||||
- **flow-chart:** fix drag and drop menu loss ([fa828fd](https://github.com/anncwb/vue-vben-admin/commit/fa828fd972efeea87f364be76a1139ae53ec20d8))
|
||||
- **form:** loss args on component change event ([513823b](https://github.com/anncwb/vue-vben-admin/commit/513823bfbd3e8acc68098e0708c34bff2dd8dba6))
|
||||
- **layout:** props warn ([#756](https://github.com/anncwb/vue-vben-admin/issues/756)) ([bbce002](https://github.com/anncwb/vue-vben-admin/commit/bbce002be170c52db984647c931db88d7724cb52))
|
||||
- **menu:** fix the jitter problem of menu folding animation,fix [#732](https://github.com/anncwb/vue-vben-admin/issues/732) ([4c89ea7](https://github.com/anncwb/vue-vben-admin/commit/4c89ea7474f4315870df1790f99f3e431f343b90))
|
||||
- **mock:** make sure ignore matches the file correctly, fix [#745](https://github.com/anncwb/vue-vben-admin/issues/745) ([a222ec8](https://github.com/anncwb/vue-vben-admin/commit/a222ec8553f9b4477a43a8f7d113b5646fbfc373))
|
||||
- **mock:** type error ([7c1ffa3](https://github.com/anncwb/vue-vben-admin/commit/7c1ffa3d23de508a8d1590985806cb7a484b24e5))
|
||||
- **modal:** add v-model support for visible ([de12bab](https://github.com/anncwb/vue-vben-admin/commit/de12babd314ac831d3cb645f42dbf8a476075623))
|
||||
- **modal:** ensure that the full screen height is calculated correctly ([1c1755c](https://github.com/anncwb/vue-vben-admin/commit/1c1755cf5b4ada7263c05ddf4105abb52a2abb2f))
|
||||
- **modal:** ensure that the shutdown event is not triggered multiple times ([655b743](https://github.com/anncwb/vue-vben-admin/commit/655b74323653147943cbde2352208cb765c82b8a))
|
||||
- **pop-confirm:** fix event working unexpected ([a6ef771](https://github.com/anncwb/vue-vben-admin/commit/a6ef771fcce14c3644c965afaa69b3a17d0a7087))
|
||||
- **route:** dynamically introduce components error ([c6b766d](https://github.com/anncwb/vue-vben-admin/commit/c6b766d8ea902294ab1f7e4a06781f2bcfdd1f0b))
|
||||
- **router:** loss `directory` route ([df8cd86](https://github.com/anncwb/vue-vben-admin/commit/df8cd860514f32f44847dcf724f0737ed4d8b9e0)), closes [#722](https://github.com/anncwb/vue-vben-admin/issues/722)
|
||||
- **store:** fix type error after pinia version upgrade ([e8d6f88](https://github.com/anncwb/vue-vben-admin/commit/e8d6f8851efd7076946486864936f1797280d3ba))
|
||||
- **table:** event editCancel loss params ([8d22231](https://github.com/anncwb/vue-vben-admin/commit/8d22231a5fa4afed19201a4a4e5c29d674498516))
|
||||
- **table:** fix table jitter problem ([8eba7fb](https://github.com/anncwb/vue-vben-admin/commit/8eba7fb52786d1977e4cb7b67673d74c91c5c827))
|
||||
- **table:** getDataSource not worked on empty data ([e78af6f](https://github.com/anncwb/vue-vben-admin/commit/e78af6f228e25f052dc4c5a1859a6db50e0b112e)), closes [#752](https://github.com/anncwb/vue-vben-admin/issues/752)
|
||||
- **table:** treeTable editable error ([4ae39c5](https://github.com/anncwb/vue-vben-admin/commit/4ae39c53b49532fc6c31086a31e30429d2e236ed)), closes [#811](https://github.com/anncwb/vue-vben-admin/issues/811)
|
||||
- **upload:** make sure to carry custom parameters, fix [#802](https://github.com/anncwb/vue-vben-admin/issues/802) ([c4b22a2](https://github.com/anncwb/vue-vben-admin/commit/c4b22a225d0088d87be0c0068f543366312521db))
|
||||
- **use-message:** `content` not support vNode ([154ebc3](https://github.com/anncwb/vue-vben-admin/commit/154ebc3d96f73bb3ceab99ea0229a3619d585aba))
|
||||
- build error ([5212ea7](https://github.com/anncwb/vue-vben-admin/commit/5212ea79b43c832a5136354b549de8f89b6e2156))
|
||||
- **avatar:** mock data and Account center style ([2066f66](https://github.com/anncwb/vue-vben-admin/commit/2066f669715491f3e91ac6d0e905cd2b3e80b58d))
|
||||
- **axios:** make sure that the parameter is an object before processing, fix [#660](https://github.com/anncwb/vue-vben-admin/issues/660) ([834fa7e](https://github.com/anncwb/vue-vben-admin/commit/834fa7eb9c8aff252e083d38fdab4f6f53b4d43a))
|
||||
- **axios:** transformRequestHook logic error ([b69dcd7](https://github.com/anncwb/vue-vben-admin/commit/b69dcd79d742fd171302ce0f48c7750d60da217f))
|
||||
- **code-editor:** fix CodeEditor style problem, fix [#655](https://github.com/anncwb/vue-vben-admin/issues/655) ([5662804](https://github.com/anncwb/vue-vben-admin/commit/566280422de0537c4e31496eaaa95a9d51fe9458))
|
||||
- **codeeditor:** empty value set failed.fixed:[#659](https://github.com/anncwb/vue-vben-admin/issues/659) ([ba2bebb](https://github.com/anncwb/vue-vben-admin/commit/ba2bebb4069085817a90d065ed5877fdb50a8039))
|
||||
- **codeMirror:** fix the JsonEditor embedded in the bullet frame causing the style to be disordered ([#668](https://github.com/anncwb/vue-vben-admin/issues/668)) ([e1123a2](https://github.com/anncwb/vue-vben-admin/commit/e1123a2ccb5d5450a5072c19e5508a5dc0f14423))
|
||||
- **demo:** fix basic form page style ([8b6e07b](https://github.com/anncwb/vue-vben-admin/commit/8b6e07b768f110f13b4f2efa6c46e03266667a8c))
|
||||
- **form:** fix form update problem ([bcad95d](https://github.com/anncwb/vue-vben-admin/commit/bcad95d32a08a73f84ecbabab409cd64159f4077)), closes [#720](https://github.com/anncwb/vue-vben-admin/issues/720)
|
||||
- **form:** radioButtonGroup value support boolean ([9e2aa20](https://github.com/anncwb/vue-vben-admin/commit/9e2aa20daa08d2902cb5d56c1560306947e44939))
|
||||
- **form:** radioButtonGroup value support number ([bbddf30](https://github.com/anncwb/vue-vben-admin/commit/bbddf30e96feb1ab048323d93d3b8c1b18857acd))
|
||||
- **form:** schemas update problem ([808328d](https://github.com/anncwb/vue-vben-admin/commit/808328dc7e56b1cc07b678d501d9589290173443)), closes [#688](https://github.com/anncwb/vue-vben-admin/issues/688)
|
||||
- **keep-alive:** tablist cache updating effect ([d62d0ca](https://github.com/anncwb/vue-vben-admin/commit/d62d0ca08cff442c23eb9265851b066a2f24afa8)), closes [#695](https://github.com/anncwb/vue-vben-admin/issues/695)
|
||||
- **layout:** fix class loss ([d018363](https://github.com/anncwb/vue-vben-admin/commit/d018363ddcd68189a18829a2b2560f3b98da58a6))
|
||||
- **layout:** fix style compatibility issues ([905e5b7](https://github.com/anncwb/vue-vben-admin/commit/905e5b714b582548f32feca723012124343686a6))
|
||||
- **lock:** fix lock modal height ([40e3cb0](https://github.com/anncwb/vue-vben-admin/commit/40e3cb043c90a8343fa44a32acad2cb77de732da)), closes [#701](https://github.com/anncwb/vue-vben-admin/issues/701)
|
||||
- **log:** fix Wrong version number ([#653](https://github.com/anncwb/vue-vben-admin/issues/653)) ([4f0d45f](https://github.com/anncwb/vue-vben-admin/commit/4f0d45f1df48755eadc0b09fa19762ee68f9abd1))
|
||||
- **login:** login page modal style fixed: [#662](https://github.com/anncwb/vue-vben-admin/issues/662) ([#666](https://github.com/anncwb/vue-vben-admin/issues/666)) ([b218f10](https://github.com/anncwb/vue-vben-admin/commit/b218f10e25a9364c399a5fe42eedb549f57c01ea))
|
||||
- **mock:** menu list api loss `type` field ([4185412](https://github.com/anncwb/vue-vben-admin/commit/41854121f3713dbde236afd3a416e9f27bd0c673))
|
||||
- **modal:** redoModalHeight not work as expected ([5d554f1](https://github.com/anncwb/vue-vben-admin/commit/5d554f184f7b61774d1a1b2e61451677b38505de))
|
||||
- **page:** `basic form` action btns should be in line ([6c4f947](https://github.com/anncwb/vue-vben-admin/commit/6c4f947386c181f45253c94e4ef735d29a253053))
|
||||
- **radio-button:** fix RadioButton `disabled` support ([ee384b1](https://github.com/anncwb/vue-vben-admin/commit/ee384b1fa7e387b3680e9d54cbe4a1e2f15ec750)), closes [#710](https://github.com/anncwb/vue-vben-admin/issues/710)
|
||||
- **table:** wrong indeterminate state ([495b1da](https://github.com/anncwb/vue-vben-admin/commit/495b1da385e9b6428d2b994669d2065722445923))
|
||||
- **table:** make sure the table width is correct, fix [#593](https://github.com/anncwb/vue-vben-admin/issues/593) ([d73d43e](https://github.com/anncwb/vue-vben-admin/commit/d73d43ed91f30957cfd202c51552ca40a19cef08))
|
||||
- **table:** settings indeterminate state effect ([4fd2051](https://github.com/anncwb/vue-vben-admin/commit/4fd2051bc0403bfc5345ed6a5fc283a372ef7a92))
|
||||
- **table:** support change event ([9f4d171](https://github.com/anncwb/vue-vben-admin/commit/9f4d1719caa76de94e6362c16e4df3ac28df253c)), closes [#677](https://github.com/anncwb/vue-vben-admin/issues/677)
|
||||
- **table:** try to get close to the form stuck ([d81481c](https://github.com/anncwb/vue-vben-admin/commit/d81481c52186145dac130aaa1594f0ba8db4d392))
|
||||
- **table:** useTable support onChange ([9f5085c](https://github.com/anncwb/vue-vben-admin/commit/9f5085c9f9f46b09391156b17091c1771bc13026))
|
||||
- **table-action:** fix the split line style is missing,fix [#674](https://github.com/anncwb/vue-vben-admin/issues/674) ([b1cb863](https://github.com/anncwb/vue-vben-admin/commit/b1cb86350253dc5be095466966d9469775f4395d))
|
||||
- **Tinymce:** Read only status upload button can also be used ([#718](https://github.com/anncwb/vue-vben-admin/issues/718)) ([966571b](https://github.com/anncwb/vue-vben-admin/commit/966571bdcb11c2729ab9ce212bd3e195f7bf3a59))
|
||||
- **upload:** ensure preview items valid ([4376928](https://github.com/anncwb/vue-vben-admin/commit/437692869a232ee65c300c65ee473557ae0913c7))
|
||||
- ensure that roleList is not empty ([aebad61](https://github.com/anncwb/vue-vben-admin/commit/aebad61b3d3e11aaf720b37e762e53e2e6999d3c))
|
||||
- fix darkModeSwitch switch failure ([34a8054](https://github.com/anncwb/vue-vben-admin/commit/34a80542de670f0385dffaf5bf64bb9c3f6b90da))
|
||||
- fix if getDropdownList.length==0 show Dropdown component ([21c771b](https://github.com/anncwb/vue-vben-admin/commit/21c771b59cb45defbff37de21c5c1950370b8f92))
|
||||
- fix Login Page LocalePicker showLocale condition ([d683b0f](https://github.com/anncwb/vue-vben-admin/commit/d683b0f1e85b85b07090feba4ac7f741bd3bd482))
|
||||
- fix node12 version data mock error ([644dbe3](https://github.com/anncwb/vue-vben-admin/commit/644dbe315bb03ea1641a682359873237208a5303))
|
||||
- Fix the problem that the `lang` attribute of `HTML` will not be set when it is first loaded ([#682](https://github.com/anncwb/vue-vben-admin/issues/682)) ([eca8907](https://github.com/anncwb/vue-vben-admin/commit/eca8907a11c28d816c3da5a0667f45a38a499012))
|
||||
- login failed ([035f55a](https://github.com/anncwb/vue-vben-admin/commit/035f55af9778819d72adc1700d9de56a6569b58f))
|
||||
- session timeout login logic error ([#678](https://github.com/anncwb/vue-vben-admin/issues/678)) ([132c7fb](https://github.com/anncwb/vue-vben-admin/commit/132c7fb944df255c4d76a25d6d924439f91f9c54)), closes [#673](https://github.com/anncwb/vue-vben-admin/issues/673)
|
||||
- **tree:** support defaultExpandAll prop ([3ed2339](https://github.com/anncwb/vue-vben-admin/commit/3ed2339a6d75abbd6ccf723b6eaa762f9921409e))
|
||||
- **useViewHeight:** Fix the problem that useContentViewHeight does not calculate the footer ([#747](https://github.com/anncwb/vue-vben-admin/issues/747)) ([33cd8fe](https://github.com/anncwb/vue-vben-admin/commit/33cd8fe6533830176ab63ddfc4d74f75a384366c))
|
||||
- theme switching fails ([7e2ca79](https://github.com/anncwb/vue-vben-admin/commit/7e2ca79ece2f5209cb7ce4b0f5ee15012f9f51de))
|
||||
|
||||
### Features
|
||||
|
||||
- **demo:** add route multi tabs show ([0e414ba](https://github.com/anncwb/vue-vben-admin/commit/0e414ba3c10b4e47a85feb1a38cae66c815719d8)), closes [#817](https://github.com/anncwb/vue-vben-admin/issues/817)
|
||||
- add Tree LoadData demo ([9298b3c](https://github.com/anncwb/vue-vben-admin/commit/9298b3c988c10b81d83430ca31b9ce1d98a3fad9))
|
||||
- optimize error message for api failure ([ea6834a](https://github.com/anncwb/vue-vben-admin/commit/ea6834aeec3ef56d411b2c10a474f75d3d7bfdfc))
|
||||
- **api-select:** auto refetch after params changed ([50207ad](https://github.com/anncwb/vue-vben-admin/commit/50207ad702ef3faca1e27c873c89132ab92fae8e))
|
||||
- **app-search:** auto focus on show ([1ae6362](https://github.com/anncwb/vue-vben-admin/commit/1ae636296df2cf99e8a777f053c539c50e6ad49a))
|
||||
- **axios:** added authenticationScheme configuration,fix [#774](https://github.com/anncwb/vue-vben-admin/issues/774) ([b6d5b07](https://github.com/anncwb/vue-vben-admin/commit/b6d5b0796de4d0b66c0f33c335ec991d44f64ef2))
|
||||
- **demo:** `switch` use in table ([46899aa](https://github.com/anncwb/vue-vben-admin/commit/46899aa3cd6b1616c42ac263a28af75be839f6a0))
|
||||
- **demo:** added guide page example ([d196340](https://github.com/anncwb/vue-vben-admin/commit/d196340d270d2becbf2cc81b7d4f09273381bd09))
|
||||
- **echarts:** add getInstance for useECharts ([fb6c76d](https://github.com/anncwb/vue-vben-admin/commit/fb6c76db535bd0c6305d03c0cff876a1f079100b))
|
||||
- **modal:** add closeModal for useModal ([6d5f9aa](https://github.com/anncwb/vue-vben-admin/commit/6d5f9aa699c5da8af6bf5841baddc4a8bd603917))
|
||||
- **modal:** add redoModalHeight for useModalInner ([f732b56](https://github.com/anncwb/vue-vben-admin/commit/f732b569042f7fe77c85cb295538ddd85561f7e9))
|
||||
- **preview:** added createImgPreview picture preview function ([305630e](https://github.com/anncwb/vue-vben-admin/commit/305630e3fd886b3f690f890a934a8a6ba224fba1))
|
||||
- **project-setting:** added sessionTimeoutProcessing project configuration item,fix [#772](https://github.com/anncwb/vue-vben-admin/issues/772) ([0d07084](https://github.com/anncwb/vue-vben-admin/commit/0d0708409c4adbe7a0c5e33abf5307031147eaeb))
|
||||
- **table:** add editable DatePicker & TimePicker ([#654](https://github.com/anncwb/vue-vben-admin/issues/654)) ([93006c7](https://github.com/anncwb/vue-vben-admin/commit/93006c7dc7b5243b26637f444c8057c95935e622))
|
||||
- **table:** add updateTableDataRecord method ([8e4f486](https://github.com/anncwb/vue-vben-admin/commit/8e4f486fcf835f0b6f2a95676dba268ffdd0566e))
|
||||
- **table:** editable component text align ([8eaf575](https://github.com/anncwb/vue-vben-admin/commit/8eaf57562610a833c8083ae9957f458319d1cc93))
|
||||
- **table:** support columns-change event ([125a7d1](https://github.com/anncwb/vue-vben-admin/commit/125a7d14831642c9cbb2e4b3e75953c3b2e2cdef))
|
||||
- **table:** support custom update on row editing ([fe2bcfc](https://github.com/anncwb/vue-vben-admin/commit/fe2bcfc6f74159c355f3be153a316869fdb8b644)), closes [#646](https://github.com/anncwb/vue-vben-admin/issues/646)
|
||||
- **table:** updateTableDataRecord support functional rowKey ([448a4c2](https://github.com/anncwb/vue-vben-admin/commit/448a4c2809672480f8f635d7cc4661554112598a))
|
||||
- **table-action:** add stopButtonPropagation prop ([808012b](https://github.com/anncwb/vue-vben-admin/commit/808012b544b8c6f3cf467f42653c2783dbe8be6b)), closes [#699](https://github.com/anncwb/vue-vben-admin/issues/699)
|
||||
- **table-img:** support simple show mode and more props ([19d8e01](https://github.com/anncwb/vue-vben-admin/commit/19d8e01e11644c66222f137abd05940cbdec0bb6))
|
||||
- **test:** add jest test suite ([f6fe1dd](https://github.com/anncwb/vue-vben-admin/commit/f6fe1dd62df231ccbd063db0d32359b48aa5c76b))
|
||||
- **use-drawer:** add closeDrawer function ([639520a](https://github.com/anncwb/vue-vben-admin/commit/639520ad5ddf829875ab517067abf2b45ebc04c2))
|
||||
- add CropperAvatar component ([8e410fc](https://github.com/anncwb/vue-vben-admin/commit/8e410fc6401847d8e5545468b5ce6fd7ce9fc5cc))
|
||||
- **tabs:** add setTabTitle method ([#680](https://github.com/anncwb/vue-vben-admin/issues/680)) ([5ddccf6](https://github.com/anncwb/vue-vben-admin/commit/5ddccf6ba28453b9a35355d53d0db65f1a8876bc))
|
||||
- **tinymce:** support dark theme and I18n ([83c9cd7](https://github.com/anncwb/vue-vben-admin/commit/83c9cd77421e9c0888a41e2d8dcbca816da67488))
|
||||
- **Tinymce:** add dynamics to the read-only state of the rich text editor ([#725](https://github.com/anncwb/vue-vben-admin/issues/725)) ([efce482](https://github.com/anncwb/vue-vben-admin/commit/efce482b3215ddf9ed588f63a218d5f76939e947))
|
||||
- **tree:** add defaultExpandLevel prop ([6edca1c](https://github.com/anncwb/vue-vben-admin/commit/6edca1c19c3b0772f9ab82a7b09251a74fff2173)), closes [#672](https://github.com/anncwb/vue-vben-admin/issues/672)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
- **component:** optimize tree and upload components ([3f6920f](https://github.com/anncwb/vue-vben-admin/commit/3f6920f7a9775fc06a34dead90b1724b23b7759c))
|
||||
- **cropper-avatar:** code optimization ([6dbbdba](https://github.com/anncwb/vue-vben-admin/commit/6dbbdbac76c2c3795e12dd346f6310d1b70f6a7d))
|
||||
- **i18n:** improve circular dependencies ([d677729](https://github.com/anncwb/vue-vben-admin/commit/d677729acbe2c024ab13cf490b205528507c4823))
|
||||
- **i18n:** improve warning prompt ([6ef62ba](https://github.com/anncwb/vue-vben-admin/commit/6ef62ba6ea7f5613a1fec982b30fe6b0f478bf59))
|
||||
- **locale:** reduce the number of multilingual files ([0acc4ab](https://github.com/anncwb/vue-vben-admin/commit/0acc4ab2dd70a239bd13929edede02b283feb7c2))
|
||||
- **pagewrapper:** 优化 PageWrapper 的高度自适应表现使用 getViewportOffset 替代 useContentViewHeight ([#792](https://github.com/anncwb/vue-vben-admin/issues/792)) ([4d8e398](https://github.com/anncwb/vue-vben-admin/commit/4d8e39857ea59fff99e69832b4a8cabf3a424c24))
|
||||
- **PageWrapper:** fix the height calculation problem when footer and global footer are opened at the same time ([#760](https://github.com/anncwb/vue-vben-admin/issues/760)) ([ab2c7ef](https://github.com/anncwb/vue-vben-admin/commit/ab2c7efe6994dacfe0ff407783f2c3b246427bfc))
|
||||
- **utils:** mitt default export is changed from Class to Function ([d3d620f](https://github.com/anncwb/vue-vben-admin/commit/d3d620f4fc75dd69270e4d090a71d426701272ef))
|
||||
- add createImgPreview func ([#713](https://github.com/anncwb/vue-vben-admin/issues/713)) ([b7c7c46](https://github.com/anncwb/vue-vben-admin/commit/b7c7c46853d332641d116d818e657447884784f3))
|
||||
- optimize components and add comments ([55e9d9f](https://github.com/anncwb/vue-vben-admin/commit/55e9d9fc2953643cec95c74b6ed34b0e68641fb6))
|
||||
|
||||
### Reverts
|
||||
|
||||
- **axios:** remove baseUrl config ([61d4efd](https://github.com/anncwb/vue-vben-admin/commit/61d4efd55a8b4f09990b5f1888e23ead43958164))
|
||||
|
||||
## [2.5.1](https://github.com/anncwb/vue-vben-admin/compare/v2.4.0...v2.5.1) (2021-06-26)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- fix antdv console warning ([480cfb9](https://github.com/anncwb/vue-vben-admin/commit/480cfb914e78c06eb7784e33465ed91b7d4c3eee))
|
||||
- fix defHttp baseUrl work ([d5f9919](https://github.com/anncwb/vue-vben-admin/commit/d5f9919b60fdd7d5c435129e8db519c0bbd37529))
|
||||
- **api:** select api type error ([b387681](https://github.com/anncwb/vue-vben-admin/commit/b387681c00ac018f5bc6a9251009ddffe37acae6))
|
||||
- **api-select:** ensure that the onchange function parameters are correct ([fa64fc8](https://github.com/anncwb/vue-vben-admin/commit/fa64fc8a622832b87fdf672965d55d543b5929a2))
|
||||
- **api-select:** loss option data on event callback ([c5f2577](https://github.com/anncwb/vue-vben-admin/commit/c5f2577f515e7ae96b27b509e5dd4b3317fcb7b4)), closes [#733](https://github.com/anncwb/vue-vben-admin/issues/733)
|
||||
- **ApiSelect demo:** add demo about ApiSelect's use ([#757](https://github.com/anncwb/vue-vben-admin/issues/757)) ([a03d3cc](https://github.com/anncwb/vue-vben-admin/commit/a03d3cc60c770eba644c1f3837850a2c1c015029))
|
||||
- **avatar:** mock data and Account center style ([2066f66](https://github.com/anncwb/vue-vben-admin/commit/2066f669715491f3e91ac6d0e905cd2b3e80b58d))
|
||||
- **axios:** make sure that the parameter is an object before processing, fix [#660](https://github.com/anncwb/vue-vben-admin/issues/660) ([834fa7e](https://github.com/anncwb/vue-vben-admin/commit/834fa7eb9c8aff252e083d38fdab4f6f53b4d43a))
|
||||
- **axios:** transformRequestHook logic error ([b69dcd7](https://github.com/anncwb/vue-vben-admin/commit/b69dcd79d742fd171302ce0f48c7750d60da217f))
|
||||
- **code-editor:** fix CodeEditor style problem, fix [#655](https://github.com/anncwb/vue-vben-admin/issues/655) ([5662804](https://github.com/anncwb/vue-vben-admin/commit/566280422de0537c4e31496eaaa95a9d51fe9458))
|
||||
- **codeeditor:** empty value set failed.fixed:[#659](https://github.com/anncwb/vue-vben-admin/issues/659) ([ba2bebb](https://github.com/anncwb/vue-vben-admin/commit/ba2bebb4069085817a90d065ed5877fdb50a8039))
|
||||
- **codeMirror:** fix the JsonEditor embedded in the bullet frame causing the style to be disordered ([#668](https://github.com/anncwb/vue-vben-admin/issues/668)) ([e1123a2](https://github.com/anncwb/vue-vben-admin/commit/e1123a2ccb5d5450a5072c19e5508a5dc0f14423))
|
||||
- **demo:** `breadcrumb` route invalid redirect ([84d9300](https://github.com/anncwb/vue-vben-admin/commit/84d9300e52fa73da575591aa4b71858a7e459c8c))
|
||||
- **demo:** account list page validate and save ([21f7a85](https://github.com/anncwb/vue-vben-admin/commit/21f7a854fe2455315287d04e895661ff739bce17))
|
||||
- **demo:** fix basic form page style ([8b6e07b](https://github.com/anncwb/vue-vben-admin/commit/8b6e07b768f110f13b4f2efa6c46e03266667a8c))
|
||||
- **demo:** make sure the map https resource is correct ([7b9cd09](https://github.com/anncwb/vue-vben-admin/commit/7b9cd09ad8a50c45b2e661e07953d786d82f367d))
|
||||
- **demo:** style error,fix [#806](https://github.com/anncwb/vue-vben-admin/issues/806) ([a2d8be3](https://github.com/anncwb/vue-vben-admin/commit/a2d8be3ab29da88126f3ba971f6893cb12327759))
|
||||
- **demo-form:** add fieldMapToTime example,fix [#807](https://github.com/anncwb/vue-vben-admin/issues/807) ([a2a75a0](https://github.com/anncwb/vue-vben-admin/commit/a2a75a097ff6c9df12471eff0d62d44d2b88cfff))
|
||||
- **design:** correct tailwind configuration,fix [#800](https://github.com/anncwb/vue-vben-admin/issues/800) ([aec230c](https://github.com/anncwb/vue-vben-admin/commit/aec230ca19d541079b64c54ba00596ef9cd92ca0))
|
||||
- **dropdown:** icon and trigger work unexpected ([60b80c9](https://github.com/anncwb/vue-vben-admin/commit/60b80c96e82da9101d56b2e195e9e7571de11f0a)), closes [#796](https://github.com/anncwb/vue-vben-admin/issues/796) [#787](https://github.com/anncwb/vue-vben-admin/issues/787)
|
||||
- **flow-chart:** fix drag and drop menu loss ([fa828fd](https://github.com/anncwb/vue-vben-admin/commit/fa828fd972efeea87f364be76a1139ae53ec20d8))
|
||||
- **form:** fix form update problem ([bcad95d](https://github.com/anncwb/vue-vben-admin/commit/bcad95d32a08a73f84ecbabab409cd64159f4077)), closes [#720](https://github.com/anncwb/vue-vben-admin/issues/720)
|
||||
- **form:** loss args on component change event ([513823b](https://github.com/anncwb/vue-vben-admin/commit/513823bfbd3e8acc68098e0708c34bff2dd8dba6))
|
||||
- **form:** radioButtonGroup value support boolean ([9e2aa20](https://github.com/anncwb/vue-vben-admin/commit/9e2aa20daa08d2902cb5d56c1560306947e44939))
|
||||
- **form:** radioButtonGroup value support number ([bbddf30](https://github.com/anncwb/vue-vben-admin/commit/bbddf30e96feb1ab048323d93d3b8c1b18857acd))
|
||||
- **form:** schemas update problem ([808328d](https://github.com/anncwb/vue-vben-admin/commit/808328dc7e56b1cc07b678d501d9589290173443)), closes [#688](https://github.com/anncwb/vue-vben-admin/issues/688)
|
||||
- **keep-alive:** tablist cache updating effect ([d62d0ca](https://github.com/anncwb/vue-vben-admin/commit/d62d0ca08cff442c23eb9265851b066a2f24afa8)), closes [#695](https://github.com/anncwb/vue-vben-admin/issues/695)
|
||||
- **layout:** fix class loss ([d018363](https://github.com/anncwb/vue-vben-admin/commit/d018363ddcd68189a18829a2b2560f3b98da58a6))
|
||||
- **layout:** fix style compatibility issues ([905e5b7](https://github.com/anncwb/vue-vben-admin/commit/905e5b714b582548f32feca723012124343686a6))
|
||||
- **layout:** props warn ([#756](https://github.com/anncwb/vue-vben-admin/issues/756)) ([bbce002](https://github.com/anncwb/vue-vben-admin/commit/bbce002be170c52db984647c931db88d7724cb52))
|
||||
- **lock:** fix lock modal height ([40e3cb0](https://github.com/anncwb/vue-vben-admin/commit/40e3cb043c90a8343fa44a32acad2cb77de732da)), closes [#701](https://github.com/anncwb/vue-vben-admin/issues/701)
|
||||
- **log:** fix Wrong version number ([#653](https://github.com/anncwb/vue-vben-admin/issues/653)) ([4f0d45f](https://github.com/anncwb/vue-vben-admin/commit/4f0d45f1df48755eadc0b09fa19762ee68f9abd1))
|
||||
- **login:** login page modal style fixed: [#662](https://github.com/anncwb/vue-vben-admin/issues/662) ([#666](https://github.com/anncwb/vue-vben-admin/issues/666)) ([b218f10](https://github.com/anncwb/vue-vben-admin/commit/b218f10e25a9364c399a5fe42eedb549f57c01ea))
|
||||
- **menu:** fix the jitter problem of menu folding animation,fix [#732](https://github.com/anncwb/vue-vben-admin/issues/732) ([4c89ea7](https://github.com/anncwb/vue-vben-admin/commit/4c89ea7474f4315870df1790f99f3e431f343b90))
|
||||
- **mock:** make sure ignore matches the file correctly, fix [#745](https://github.com/anncwb/vue-vben-admin/issues/745) ([a222ec8](https://github.com/anncwb/vue-vben-admin/commit/a222ec8553f9b4477a43a8f7d113b5646fbfc373))
|
||||
- **mock:** menu list api loss `type` field ([4185412](https://github.com/anncwb/vue-vben-admin/commit/41854121f3713dbde236afd3a416e9f27bd0c673))
|
||||
- **mock:** type error ([7c1ffa3](https://github.com/anncwb/vue-vben-admin/commit/7c1ffa3d23de508a8d1590985806cb7a484b24e5))
|
||||
- **modal:** add v-model support for visible ([de12bab](https://github.com/anncwb/vue-vben-admin/commit/de12babd314ac831d3cb645f42dbf8a476075623))
|
||||
- **modal:** ensure that the full screen height is calculated correctly ([1c1755c](https://github.com/anncwb/vue-vben-admin/commit/1c1755cf5b4ada7263c05ddf4105abb52a2abb2f))
|
||||
- **modal:** ensure that the shutdown event is not triggered multiple times ([655b743](https://github.com/anncwb/vue-vben-admin/commit/655b74323653147943cbde2352208cb765c82b8a))
|
||||
- **modal:** redoModalHeight not work as expected ([5d554f1](https://github.com/anncwb/vue-vben-admin/commit/5d554f184f7b61774d1a1b2e61451677b38505de))
|
||||
- **page:** `basic form` action btns should be in line ([6c4f947](https://github.com/anncwb/vue-vben-admin/commit/6c4f947386c181f45253c94e4ef735d29a253053))
|
||||
- **pop-confirm:** fix event working unexpected ([a6ef771](https://github.com/anncwb/vue-vben-admin/commit/a6ef771fcce14c3644c965afaa69b3a17d0a7087))
|
||||
- **radio-button:** fix RadioButton `disabled` support ([ee384b1](https://github.com/anncwb/vue-vben-admin/commit/ee384b1fa7e387b3680e9d54cbe4a1e2f15ec750)), closes [#710](https://github.com/anncwb/vue-vben-admin/issues/710)
|
||||
- **route:** dynamically introduce components error ([c6b766d](https://github.com/anncwb/vue-vben-admin/commit/c6b766d8ea902294ab1f7e4a06781f2bcfdd1f0b))
|
||||
- **router:** loss `directory` route ([df8cd86](https://github.com/anncwb/vue-vben-admin/commit/df8cd860514f32f44847dcf724f0737ed4d8b9e0)), closes [#722](https://github.com/anncwb/vue-vben-admin/issues/722)
|
||||
- **store:** fix type error after pinia version upgrade ([e8d6f88](https://github.com/anncwb/vue-vben-admin/commit/e8d6f8851efd7076946486864936f1797280d3ba))
|
||||
- **table:** wrong indeterminate state ([495b1da](https://github.com/anncwb/vue-vben-admin/commit/495b1da385e9b6428d2b994669d2065722445923))
|
||||
- **table:** event editCancel loss params ([8d22231](https://github.com/anncwb/vue-vben-admin/commit/8d22231a5fa4afed19201a4a4e5c29d674498516))
|
||||
- **table:** fix table jitter problem ([8eba7fb](https://github.com/anncwb/vue-vben-admin/commit/8eba7fb52786d1977e4cb7b67673d74c91c5c827))
|
||||
- **table:** getDataSource not worked on empty data ([e78af6f](https://github.com/anncwb/vue-vben-admin/commit/e78af6f228e25f052dc4c5a1859a6db50e0b112e)), closes [#752](https://github.com/anncwb/vue-vben-admin/issues/752)
|
||||
- **table:** make sure the table width is correct, fix [#593](https://github.com/anncwb/vue-vben-admin/issues/593) ([d73d43e](https://github.com/anncwb/vue-vben-admin/commit/d73d43ed91f30957cfd202c51552ca40a19cef08))
|
||||
- **table:** settings indeterminate state effect ([4fd2051](https://github.com/anncwb/vue-vben-admin/commit/4fd2051bc0403bfc5345ed6a5fc283a372ef7a92))
|
||||
- **table:** support change event ([9f4d171](https://github.com/anncwb/vue-vben-admin/commit/9f4d1719caa76de94e6362c16e4df3ac28df253c)), closes [#677](https://github.com/anncwb/vue-vben-admin/issues/677)
|
||||
- **table:** treeTable editable error ([4ae39c5](https://github.com/anncwb/vue-vben-admin/commit/4ae39c53b49532fc6c31086a31e30429d2e236ed)), closes [#811](https://github.com/anncwb/vue-vben-admin/issues/811)
|
||||
- **table:** try to get close to the form stuck ([d81481c](https://github.com/anncwb/vue-vben-admin/commit/d81481c52186145dac130aaa1594f0ba8db4d392))
|
||||
- **table:** useTable support onChange ([9f5085c](https://github.com/anncwb/vue-vben-admin/commit/9f5085c9f9f46b09391156b17091c1771bc13026))
|
||||
- **table-action:** fix the split line style is missing,fix [#674](https://github.com/anncwb/vue-vben-admin/issues/674) ([b1cb863](https://github.com/anncwb/vue-vben-admin/commit/b1cb86350253dc5be095466966d9469775f4395d))
|
||||
- **Tinymce:** Read only status upload button can also be used ([#718](https://github.com/anncwb/vue-vben-admin/issues/718)) ([966571b](https://github.com/anncwb/vue-vben-admin/commit/966571bdcb11c2729ab9ce212bd3e195f7bf3a59))
|
||||
- **upload:** ensure preview items valid ([4376928](https://github.com/anncwb/vue-vben-admin/commit/437692869a232ee65c300c65ee473557ae0913c7))
|
||||
- **upload:** make sure to carry custom parameters, fix [#802](https://github.com/anncwb/vue-vben-admin/issues/802) ([c4b22a2](https://github.com/anncwb/vue-vben-admin/commit/c4b22a225d0088d87be0c0068f543366312521db))
|
||||
- **use-message:** `content` not support vNode ([154ebc3](https://github.com/anncwb/vue-vben-admin/commit/154ebc3d96f73bb3ceab99ea0229a3619d585aba))
|
||||
- build error ([5212ea7](https://github.com/anncwb/vue-vben-admin/commit/5212ea79b43c832a5136354b549de8f89b6e2156))
|
||||
- ensure that roleList is not empty ([aebad61](https://github.com/anncwb/vue-vben-admin/commit/aebad61b3d3e11aaf720b37e762e53e2e6999d3c))
|
||||
- fix darkModeSwitch switch failure ([34a8054](https://github.com/anncwb/vue-vben-admin/commit/34a80542de670f0385dffaf5bf64bb9c3f6b90da))
|
||||
- fix if getDropdownList.length==0 show Dropdown component ([21c771b](https://github.com/anncwb/vue-vben-admin/commit/21c771b59cb45defbff37de21c5c1950370b8f92))
|
||||
- fix Login Page LocalePicker showLocale condition ([d683b0f](https://github.com/anncwb/vue-vben-admin/commit/d683b0f1e85b85b07090feba4ac7f741bd3bd482))
|
||||
- fix node12 version data mock error ([644dbe3](https://github.com/anncwb/vue-vben-admin/commit/644dbe315bb03ea1641a682359873237208a5303))
|
||||
- Fix the problem that the `lang` attribute of `HTML` will not be set when it is first loaded ([#682](https://github.com/anncwb/vue-vben-admin/issues/682)) ([eca8907](https://github.com/anncwb/vue-vben-admin/commit/eca8907a11c28d816c3da5a0667f45a38a499012))
|
||||
- login failed ([035f55a](https://github.com/anncwb/vue-vben-admin/commit/035f55af9778819d72adc1700d9de56a6569b58f))
|
||||
- session timeout login logic error ([#678](https://github.com/anncwb/vue-vben-admin/issues/678)) ([132c7fb](https://github.com/anncwb/vue-vben-admin/commit/132c7fb944df255c4d76a25d6d924439f91f9c54)), closes [#673](https://github.com/anncwb/vue-vben-admin/issues/673)
|
||||
- **tree:** support defaultExpandAll prop ([3ed2339](https://github.com/anncwb/vue-vben-admin/commit/3ed2339a6d75abbd6ccf723b6eaa762f9921409e))
|
||||
- **useViewHeight:** Fix the problem that useContentViewHeight does not calculate the footer ([#747](https://github.com/anncwb/vue-vben-admin/issues/747)) ([33cd8fe](https://github.com/anncwb/vue-vben-admin/commit/33cd8fe6533830176ab63ddfc4d74f75a384366c))
|
||||
- theme switching fails ([7e2ca79](https://github.com/anncwb/vue-vben-admin/commit/7e2ca79ece2f5209cb7ce4b0f5ee15012f9f51de))
|
||||
|
||||
### Features
|
||||
|
||||
- **demo:** add route multi tabs show ([0e414ba](https://github.com/anncwb/vue-vben-admin/commit/0e414ba3c10b4e47a85feb1a38cae66c815719d8)), closes [#817](https://github.com/anncwb/vue-vben-admin/issues/817)
|
||||
- add Tree LoadData demo ([9298b3c](https://github.com/anncwb/vue-vben-admin/commit/9298b3c988c10b81d83430ca31b9ce1d98a3fad9))
|
||||
- optimize error message for api failure ([ea6834a](https://github.com/anncwb/vue-vben-admin/commit/ea6834aeec3ef56d411b2c10a474f75d3d7bfdfc))
|
||||
- **api-select:** auto refetch after params changed ([50207ad](https://github.com/anncwb/vue-vben-admin/commit/50207ad702ef3faca1e27c873c89132ab92fae8e))
|
||||
- **app-search:** auto focus on show ([1ae6362](https://github.com/anncwb/vue-vben-admin/commit/1ae636296df2cf99e8a777f053c539c50e6ad49a))
|
||||
- **axios:** added authenticationScheme configuration,fix [#774](https://github.com/anncwb/vue-vben-admin/issues/774) ([b6d5b07](https://github.com/anncwb/vue-vben-admin/commit/b6d5b0796de4d0b66c0f33c335ec991d44f64ef2))
|
||||
- **demo:** `switch` use in table ([46899aa](https://github.com/anncwb/vue-vben-admin/commit/46899aa3cd6b1616c42ac263a28af75be839f6a0))
|
||||
- **demo:** added guide page example ([d196340](https://github.com/anncwb/vue-vben-admin/commit/d196340d270d2becbf2cc81b7d4f09273381bd09))
|
||||
- **echarts:** add getInstance for useECharts ([fb6c76d](https://github.com/anncwb/vue-vben-admin/commit/fb6c76db535bd0c6305d03c0cff876a1f079100b))
|
||||
- **modal:** add closeModal for useModal ([6d5f9aa](https://github.com/anncwb/vue-vben-admin/commit/6d5f9aa699c5da8af6bf5841baddc4a8bd603917))
|
||||
- **modal:** add redoModalHeight for useModalInner ([f732b56](https://github.com/anncwb/vue-vben-admin/commit/f732b569042f7fe77c85cb295538ddd85561f7e9))
|
||||
- **preview:** added createImgPreview picture preview function ([305630e](https://github.com/anncwb/vue-vben-admin/commit/305630e3fd886b3f690f890a934a8a6ba224fba1))
|
||||
- **project-setting:** added sessionTimeoutProcessing project configuration item,fix [#772](https://github.com/anncwb/vue-vben-admin/issues/772) ([0d07084](https://github.com/anncwb/vue-vben-admin/commit/0d0708409c4adbe7a0c5e33abf5307031147eaeb))
|
||||
- **table:** add editable DatePicker & TimePicker ([#654](https://github.com/anncwb/vue-vben-admin/issues/654)) ([93006c7](https://github.com/anncwb/vue-vben-admin/commit/93006c7dc7b5243b26637f444c8057c95935e622))
|
||||
- **table:** add updateTableDataRecord method ([8e4f486](https://github.com/anncwb/vue-vben-admin/commit/8e4f486fcf835f0b6f2a95676dba268ffdd0566e))
|
||||
- **table:** editable component text align ([8eaf575](https://github.com/anncwb/vue-vben-admin/commit/8eaf57562610a833c8083ae9957f458319d1cc93))
|
||||
- **table:** support columns-change event ([125a7d1](https://github.com/anncwb/vue-vben-admin/commit/125a7d14831642c9cbb2e4b3e75953c3b2e2cdef))
|
||||
- **table:** support custom update on row editing ([fe2bcfc](https://github.com/anncwb/vue-vben-admin/commit/fe2bcfc6f74159c355f3be153a316869fdb8b644)), closes [#646](https://github.com/anncwb/vue-vben-admin/issues/646)
|
||||
- **table:** updateTableDataRecord support functional rowKey ([448a4c2](https://github.com/anncwb/vue-vben-admin/commit/448a4c2809672480f8f635d7cc4661554112598a))
|
||||
- **table-action:** add stopButtonPropagation prop ([808012b](https://github.com/anncwb/vue-vben-admin/commit/808012b544b8c6f3cf467f42653c2783dbe8be6b)), closes [#699](https://github.com/anncwb/vue-vben-admin/issues/699)
|
||||
- **table-img:** support simple show mode and more props ([19d8e01](https://github.com/anncwb/vue-vben-admin/commit/19d8e01e11644c66222f137abd05940cbdec0bb6))
|
||||
- **test:** add jest test suite ([f6fe1dd](https://github.com/anncwb/vue-vben-admin/commit/f6fe1dd62df231ccbd063db0d32359b48aa5c76b))
|
||||
- **use-drawer:** add closeDrawer function ([639520a](https://github.com/anncwb/vue-vben-admin/commit/639520ad5ddf829875ab517067abf2b45ebc04c2))
|
||||
- add CropperAvatar component ([8e410fc](https://github.com/anncwb/vue-vben-admin/commit/8e410fc6401847d8e5545468b5ce6fd7ce9fc5cc))
|
||||
- **tabs:** add setTabTitle method ([#680](https://github.com/anncwb/vue-vben-admin/issues/680)) ([5ddccf6](https://github.com/anncwb/vue-vben-admin/commit/5ddccf6ba28453b9a35355d53d0db65f1a8876bc))
|
||||
- **tinymce:** support dark theme and I18n ([83c9cd7](https://github.com/anncwb/vue-vben-admin/commit/83c9cd77421e9c0888a41e2d8dcbca816da67488))
|
||||
- **Tinymce:** add dynamics to the read-only state of the rich text editor ([#725](https://github.com/anncwb/vue-vben-admin/issues/725)) ([efce482](https://github.com/anncwb/vue-vben-admin/commit/efce482b3215ddf9ed588f63a218d5f76939e947))
|
||||
- **tree:** add defaultExpandLevel prop ([6edca1c](https://github.com/anncwb/vue-vben-admin/commit/6edca1c19c3b0772f9ab82a7b09251a74fff2173)), closes [#672](https://github.com/anncwb/vue-vben-admin/issues/672)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
- **component:** optimize tree and upload components ([3f6920f](https://github.com/anncwb/vue-vben-admin/commit/3f6920f7a9775fc06a34dead90b1724b23b7759c))
|
||||
- **cropper-avatar:** code optimization ([6dbbdba](https://github.com/anncwb/vue-vben-admin/commit/6dbbdbac76c2c3795e12dd346f6310d1b70f6a7d))
|
||||
- **i18n:** improve circular dependencies ([d677729](https://github.com/anncwb/vue-vben-admin/commit/d677729acbe2c024ab13cf490b205528507c4823))
|
||||
- **i18n:** improve warning prompt ([6ef62ba](https://github.com/anncwb/vue-vben-admin/commit/6ef62ba6ea7f5613a1fec982b30fe6b0f478bf59))
|
||||
- **locale:** reduce the number of multilingual files ([0acc4ab](https://github.com/anncwb/vue-vben-admin/commit/0acc4ab2dd70a239bd13929edede02b283feb7c2))
|
||||
- **pagewrapper:** 优化 PageWrapper 的高度自适应表现使用 getViewportOffset 替代 useContentViewHeight ([#792](https://github.com/anncwb/vue-vben-admin/issues/792)) ([4d8e398](https://github.com/anncwb/vue-vben-admin/commit/4d8e39857ea59fff99e69832b4a8cabf3a424c24))
|
||||
- **PageWrapper:** fix the height calculation problem when footer and global footer are opened at the same time ([#760](https://github.com/anncwb/vue-vben-admin/issues/760)) ([ab2c7ef](https://github.com/anncwb/vue-vben-admin/commit/ab2c7efe6994dacfe0ff407783f2c3b246427bfc))
|
||||
- **utils:** mitt default export is changed from Class to Function ([d3d620f](https://github.com/anncwb/vue-vben-admin/commit/d3d620f4fc75dd69270e4d090a71d426701272ef))
|
||||
- add createImgPreview func ([#713](https://github.com/anncwb/vue-vben-admin/issues/713)) ([b7c7c46](https://github.com/anncwb/vue-vben-admin/commit/b7c7c46853d332641d116d818e657447884784f3))
|
||||
- optimize components and add comments ([55e9d9f](https://github.com/anncwb/vue-vben-admin/commit/55e9d9fc2953643cec95c74b6ed34b0e68641fb6))
|
||||
|
||||
### Reverts
|
||||
|
||||
- **axios:** remove baseUrl config ([61d4efd](https://github.com/anncwb/vue-vben-admin/commit/61d4efd55a8b4f09990b5f1888e23ead43958164))
|
||||
|
||||
# [2.5.0](https://github.com/anncwb/vue-vben-admin/compare/v2.4.0...v2.5.0) (2021-06-20)
|
||||
|
||||
### Bug Fixes
|
||||
|
@@ -1,3 +1,128 @@
|
||||
## 2.6.1(2021-07-19)
|
||||
|
||||
### ✨ Features
|
||||
|
||||
- **NoticeList** 添加分页、超长自动省略、标题点击事件、标题删除线等功能
|
||||
- **MixSider** 优化 Mix 菜单布局时 底部折叠按钮 的样式,与其它菜单布局时的风格保持一致
|
||||
- **ApiTreeSelect** 扩展`antdv`的`TreeSelect`组件,支持远程数据源,用法类似`ApiSelect`
|
||||
- **BasicTable** 新增`ApiTreeSelect`编辑组件
|
||||
- 可以为不同的用户指定不同的后台首页:
|
||||
- 在`getUserInfo`接口返回的用户信息中增加`homePath`字段(可选)即可为当前用户定制首页路径
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- **BasicTable**
|
||||
- 修复滚动条样式问题(移除了滚动样式补丁)
|
||||
- 修复树形表格的带有展开图标的单元格的内容对齐问题
|
||||
- 新增`headerTop`插槽
|
||||
- 修复操作列的按钮在 disabled 状态下的颜色显示
|
||||
- 修复可编辑单元格的值不能直接通过修改`dataSource`来更新显示的问题
|
||||
- 修复使用`ApiSelect`编辑组件时的数据回显问题
|
||||
- 修复在部分场景下编辑组件可能会报`onXXX`类型错误的问题
|
||||
- **TableAction**
|
||||
- 仅在 `action.tooltip`存在的情况下 才创建 Tooltip 组件
|
||||
- 修复组件内的圆形按钮内容没有居中的问题
|
||||
- **AppSearch** 修复可能会搜索隐藏菜单的问题
|
||||
- **BasicUpload** 修复处理非`array`值时报错的问题
|
||||
- **Form** 修复`FormItem`的`suffix`插槽样式问题
|
||||
- **Menu**
|
||||
- 修复左侧混合菜单的悬停触发逻辑
|
||||
- 修复顶栏菜单在显示包含需要隐藏的菜单项目时出错的问题
|
||||
- 修复悬停触发模式下左侧混合菜单会在没有子菜单且被激活时直接跳转路由
|
||||
- **Breadcrumb** 修复带有重定向的菜单点击无法跳转的问题
|
||||
- **Markdown** 修复初始化异常以及不能正确地动态设置 value 的问题
|
||||
- **Modal** 确保 props 正确被传递
|
||||
- **MultipleTab** 修复可能会意外创建登录路由标签的问题
|
||||
- **BasicTree** 修复搜索功能可能导致`checkedKeys`丢失的问题
|
||||
- **CodeEditor** 修复 value 不支持 v-model 用法的问题
|
||||
- **CountdownInput** 修复不支持`input`插槽的问题
|
||||
- **ApiSelect** 修复`options-change`事件参数不是`select`所使用的标准`options`数据的问题
|
||||
- **其它**
|
||||
- 修复菜单默认折叠的配置不起作用的问题
|
||||
- 修复`safari`浏览器报错导致网站打不开
|
||||
- 修复在 window 上,拉取代码后 eslint 因 endOfLine 而保错问题
|
||||
- 修复因动态路由而产生的 `Vue Router warn`
|
||||
|
||||
### 🎫 Chores
|
||||
|
||||
- 添加 test 环境测试命令
|
||||
|
||||
## 2.6.0(2021-07-04)
|
||||
|
||||
### ✨ Features
|
||||
|
||||
- **Axios** 新增`withToken`配置,用于控制请求是否携带 token
|
||||
- **BasicUpload**
|
||||
- 新增在预览 `Modal` 中删除文件时触发`preview-delete` 事件
|
||||
- `value` 支持 `v-model` 用法
|
||||
- **Route 配置**
|
||||
- 增加`ignoreRoute`用于在`ROUTE_MAPPING`或`BACK`权限模式下仅生成菜单
|
||||
- 增加`hidePathForChildren`配置,标识为子项目生成菜单时忽略本级`path`
|
||||
- **TableAction** 新增`tooltip`配置,可以为按钮增加 tooltip 提示
|
||||
- **CropperAvatar**
|
||||
- 新增`value`用于设置当前头像
|
||||
- 新增`onChange`用于接受头像剪裁并上传成功事件
|
||||
- 新增`btnText`、`btnProps` 用于自定义上传按钮文案和属性
|
||||
- 为剪裁`Modal`内的操作按钮添加工具提示
|
||||
- **Modal** 为右上角的操作按钮添加工具提示
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- **Modal**
|
||||
- 修复点击遮罩不能关闭的问题
|
||||
- 修复 `setModalProps` 不支持设置 `defaultFullscreen` 的问题
|
||||
- **Table**
|
||||
- 修复 `editComponentProps` 不支持 `onChange`的问题
|
||||
- 修复启用`clickToRowSelect`时,点击行不会触发`selection-change`事件的问题
|
||||
- 修复全局配置`fetchSetting`可能会被局部配置意外修改的问题
|
||||
- 修复`handleSearchInfoFn`的参数包含多余空白键的问题
|
||||
- 修复为 table 提供 rowSelection.onChange 时,无法手动变更 table 的选中项的问题
|
||||
- 修复滚动条在无需显示的时候仍然持续显示的问题
|
||||
- **Icon** 修复 SvgIcon 缺少部分样式的问题
|
||||
- **Menu**
|
||||
- 修复路由映射模式下,单级菜单刷新不会激活
|
||||
- 修复侧边菜单底部的折叠自定义失效的问题
|
||||
- **Form** 修复`submitButtonOptions`和`resetButtonOptions`的类型定义
|
||||
- **PopConfirmButton** 移除`Button`上多余的`title`
|
||||
- **Axios** 修复非`GET`请求时,无法同时提交`params`和`data`数据的问题
|
||||
- **其它**
|
||||
- 修复锁屏功能可以通过刷新页面或复制 URL 打开新的浏览器标签来跳过锁定状态的问题
|
||||
- 修复多个窗口同时打开页面时,`Token` 不会同步的问题
|
||||
- 修复`ROLE`权限模式下`hasPermission`不工作的问题
|
||||
- **Table** 修复`handleSearchInfoFn`的参数包含多余空白键的问题
|
||||
- **Tailwindcss** 移除控制台警告
|
||||
|
||||
## 2.5.2(2021-06-27)
|
||||
|
||||
### ⚡ Performance Improvements
|
||||
|
||||
- **Icon** 移除 Icon 组件全局注册,防止特定情况下热更新问题
|
||||
|
||||
### ✨ Features
|
||||
|
||||
- **Menu** 新增 `permissionMode=PermissionModeEnum.ROUTE_MAPPING`模式
|
||||
- 项目默认改为该模式,删除原有菜单文件
|
||||
- 如果之前已经写好了菜单,可以更改为`PermissionModeEnum.ROLE`模式即可
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- **Drawer** 修复`visible`状态异常
|
||||
|
||||
## 2.5.1(2021-06-26)
|
||||
|
||||
### ⚡ Performance Improvements
|
||||
|
||||
- 升级`vue`与`ant-design-vue`版本,解决兼容问题
|
||||
- **Tree** 性能优化
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- **Table** 修复分页抖动问题
|
||||
- **Upload** 确保携带自定义参数
|
||||
- **Dropdown** 修复 popConfirm 的图标显示问题
|
||||
- **Table** 修复树形表格的编辑事件不正常的问题
|
||||
- **Table** 修复当表格数据为空时,getDataSource 返回的值不是表格所使用的数据源的问题
|
||||
|
||||
## 2.5.0(2021-06-20)
|
||||
|
||||
## (破坏性更新) Breaking changes
|
||||
|
@@ -39,22 +39,37 @@ export function wrapperEnv(envConf: Recordable): ViteEnv {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前环境下生效的配置文件名
|
||||
*/
|
||||
function getConfFiles() {
|
||||
const script = process.env.npm_lifecycle_script;
|
||||
const reg = new RegExp('--mode ([a-z]+)');
|
||||
const result = reg.exec(script as string) as any;
|
||||
if (result) {
|
||||
const mode = result[1] as string;
|
||||
return ['.env', `.env.${mode}`];
|
||||
}
|
||||
return ['.env', '.env.production'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the environment variables starting with the specified prefix
|
||||
* @param match prefix
|
||||
* @param confFiles ext
|
||||
*/
|
||||
export function getEnvConfig(match = 'VITE_GLOB_', confFiles = ['.env', '.env.production']) {
|
||||
export function getEnvConfig(match = 'VITE_GLOB_', confFiles = getConfFiles()) {
|
||||
let envConfig = {};
|
||||
confFiles.forEach((item) => {
|
||||
try {
|
||||
const env = dotenv.parse(fs.readFileSync(path.resolve(process.cwd(), item)));
|
||||
envConfig = { ...envConfig, ...env };
|
||||
} catch (error) {}
|
||||
} catch (e) {
|
||||
console.error(`Error in parsing ${item}`, e);
|
||||
}
|
||||
});
|
||||
|
||||
const reg = new RegExp(`^(${match})`);
|
||||
Object.keys(envConfig).forEach((key) => {
|
||||
const reg = new RegExp(`^(${match})`);
|
||||
if (!reg.test(key)) {
|
||||
Reflect.deleteProperty(envConfig, key);
|
||||
}
|
||||
|
@@ -13,7 +13,7 @@ export function configImageminPlugin() {
|
||||
optimizationLevel: 7,
|
||||
},
|
||||
mozjpeg: {
|
||||
quality: 8,
|
||||
quality: 20,
|
||||
},
|
||||
pngquant: {
|
||||
quality: [0.8, 0.9],
|
||||
@@ -22,10 +22,11 @@ export function configImageminPlugin() {
|
||||
svgo: {
|
||||
plugins: [
|
||||
{
|
||||
removeViewBox: false,
|
||||
name: 'removeViewBox',
|
||||
},
|
||||
{
|
||||
removeEmptyAttrs: false,
|
||||
name: 'removeEmptyAttrs',
|
||||
active: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@@ -1,31 +1,6 @@
|
||||
module.exports = {
|
||||
ignores: [(commit) => commit.includes('init')],
|
||||
extends: ['@commitlint/config-conventional'],
|
||||
parserPreset: {
|
||||
parserOpts: {
|
||||
headerPattern: /^(\w*|[\u4e00-\u9fa5]*)(?:[\(\(](.*)[\)\)])?[\:\:] (.*)/,
|
||||
headerCorrespondence: ['type', 'scope', 'subject'],
|
||||
referenceActions: [
|
||||
'close',
|
||||
'closes',
|
||||
'closed',
|
||||
'fix',
|
||||
'fixes',
|
||||
'fixed',
|
||||
'resolve',
|
||||
'resolves',
|
||||
'resolved',
|
||||
],
|
||||
issuePrefixes: ['#'],
|
||||
noteKeywords: ['BREAKING CHANGE'],
|
||||
fieldPattern: /^-(.*?)-$/,
|
||||
revertPattern: /^Revert\s"([\s\S]*)"\s*This reverts commit (\w*)\./,
|
||||
revertCorrespondence: ['header', 'hash'],
|
||||
warn() {},
|
||||
mergePattern: null,
|
||||
mergeCorrespondence: null,
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
'body-leading-blank': [2, 'always'],
|
||||
'footer-leading-blank': [1, 'always'],
|
||||
|
@@ -1,28 +1,28 @@
|
||||
import { MockMethod } from 'vite-plugin-mock';
|
||||
import { resultSuccess } from '../_util';
|
||||
|
||||
const list: any[] = [];
|
||||
const demoList = (() => {
|
||||
const demoList = (keyword) => {
|
||||
const result = {
|
||||
list: list,
|
||||
list: [] as any[],
|
||||
};
|
||||
for (let index = 0; index < 20; index++) {
|
||||
result.list.push({
|
||||
name: `选项${index}`,
|
||||
name: `${keyword ?? ''}选项${index}`,
|
||||
id: `${index}`,
|
||||
});
|
||||
}
|
||||
return result;
|
||||
})();
|
||||
};
|
||||
|
||||
export default [
|
||||
{
|
||||
url: '/basic-api/select/getDemoOptions',
|
||||
timeout: 1000,
|
||||
method: 'post',
|
||||
method: 'get',
|
||||
response: ({ query }) => {
|
||||
console.log(query);
|
||||
return resultSuccess(demoList);
|
||||
const { keyword } = query;
|
||||
console.log(keyword);
|
||||
return resultSuccess(demoList(keyword));
|
||||
},
|
||||
},
|
||||
] as MockMethod[];
|
||||
|
38
mock/demo/tree-demo.ts
Normal file
38
mock/demo/tree-demo.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import { MockMethod } from 'vite-plugin-mock';
|
||||
import { resultSuccess } from '../_util';
|
||||
|
||||
const demoTreeList = (keyword) => {
|
||||
const result = {
|
||||
list: [] as Recordable[],
|
||||
};
|
||||
for (let index = 0; index < 5; index++) {
|
||||
const children: Recordable[] = [];
|
||||
for (let j = 0; j < 3; j++) {
|
||||
children.push({
|
||||
title: `${keyword ?? ''}选项${index}-${j}`,
|
||||
value: `${index}-${j}`,
|
||||
key: `${index}-${j}`,
|
||||
});
|
||||
}
|
||||
result.list.push({
|
||||
title: `${keyword ?? ''}选项${index}`,
|
||||
value: `${index}`,
|
||||
key: `${index}`,
|
||||
children,
|
||||
});
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
export default [
|
||||
{
|
||||
url: '/basic-api/tree/getDemoOptions',
|
||||
timeout: 1000,
|
||||
method: 'get',
|
||||
response: ({ query }) => {
|
||||
const { keyword } = query;
|
||||
console.log(keyword);
|
||||
return resultSuccess(demoTreeList(keyword));
|
||||
},
|
||||
},
|
||||
] as MockMethod[];
|
@@ -5,13 +5,40 @@ import { createFakeUserList } from './user';
|
||||
// single
|
||||
const dashboardRoute = {
|
||||
path: '/dashboard',
|
||||
name: 'Welcome',
|
||||
component: '/dashboard/analysis/index',
|
||||
name: 'Dashboard',
|
||||
component: 'LAYOUT',
|
||||
redirect: '/dashboard/analysis',
|
||||
meta: {
|
||||
title: 'routes.dashboard.analysis',
|
||||
affix: true,
|
||||
title: 'routes.dashboard.dashboard',
|
||||
hideChildrenInMenu: true,
|
||||
icon: 'bx:bx-home',
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'analysis',
|
||||
name: 'Analysis',
|
||||
component: '/dashboard/analysis/index',
|
||||
meta: {
|
||||
hideMenu: true,
|
||||
hideBreadcrumb: true,
|
||||
title: 'routes.dashboard.analysis',
|
||||
currentActiveMenu: '/dashboard',
|
||||
icon: 'bx:bx-home',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'workbench',
|
||||
name: 'Workbench',
|
||||
component: '/dashboard/workbench/index',
|
||||
meta: {
|
||||
hideMenu: true,
|
||||
hideBreadcrumb: true,
|
||||
title: 'routes.dashboard.workbench',
|
||||
currentActiveMenu: '/dashboard',
|
||||
icon: 'bx:bx-home',
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const backRoute = {
|
||||
@@ -128,6 +155,18 @@ const sysRoute = {
|
||||
},
|
||||
component: '/demo/system/account/index',
|
||||
},
|
||||
{
|
||||
path: 'account_detail/:id',
|
||||
name: 'AccountDetail',
|
||||
meta: {
|
||||
hideMenu: true,
|
||||
title: 'routes.demo.system.account_detail',
|
||||
ignoreKeepAlive: true,
|
||||
showMenu: false,
|
||||
currentActiveMenu: '/system/account',
|
||||
},
|
||||
component: '/demo/system/account/AccountDetail',
|
||||
},
|
||||
{
|
||||
path: 'role',
|
||||
name: 'RoleManagement',
|
||||
@@ -211,12 +250,21 @@ export default [
|
||||
return resultError('Invalid user token!');
|
||||
}
|
||||
const id = checkUser.userId;
|
||||
if (!id || id === '1') {
|
||||
return resultSuccess([dashboardRoute, authRoute, levelRoute, sysRoute, linkRoute]);
|
||||
}
|
||||
if (id === '2') {
|
||||
return resultSuccess([dashboardRoute, authRoute, levelRoute, linkRoute]);
|
||||
let menu: Object[];
|
||||
switch (id) {
|
||||
case '1':
|
||||
dashboardRoute.redirect = dashboardRoute.path + '/' + dashboardRoute.children[0].path;
|
||||
menu = [dashboardRoute, authRoute, levelRoute, sysRoute, linkRoute];
|
||||
break;
|
||||
case '2':
|
||||
dashboardRoute.redirect = dashboardRoute.path + '/' + dashboardRoute.children[1].path;
|
||||
menu = [dashboardRoute, authRoute, levelRoute, linkRoute];
|
||||
break;
|
||||
default:
|
||||
menu = [];
|
||||
}
|
||||
|
||||
return resultSuccess(menu);
|
||||
},
|
||||
},
|
||||
] as MockMethod[];
|
||||
|
@@ -11,6 +11,7 @@ export function createFakeUserList() {
|
||||
desc: 'manager',
|
||||
password: '123456',
|
||||
token: 'fakeToken1',
|
||||
homePath: '/dashboard/analysis',
|
||||
roles: [
|
||||
{
|
||||
roleName: 'Super Admin',
|
||||
@@ -26,6 +27,7 @@ export function createFakeUserList() {
|
||||
avatar: 'https://q1.qlogo.cn/g?b=qq&nk=339449197&s=640',
|
||||
desc: 'tester',
|
||||
token: 'fakeToken2',
|
||||
homePath: '/dashboard/workbench',
|
||||
roles: [
|
||||
{
|
||||
roleName: 'Tester',
|
||||
@@ -95,4 +97,18 @@ export default [
|
||||
return resultSuccess(codeList);
|
||||
},
|
||||
},
|
||||
{
|
||||
url: '/basic-api/logout',
|
||||
timeout: 200,
|
||||
method: 'get',
|
||||
response: (request: requestParams) => {
|
||||
const token = getRequestToken(request);
|
||||
if (!token) return resultError('Invalid token');
|
||||
const checkUser = createFakeUserList().find((item) => item.token === token);
|
||||
if (!checkUser) {
|
||||
return resultError('Invalid token!');
|
||||
}
|
||||
return resultSuccess(undefined, { message: 'Token has been destroyed' });
|
||||
},
|
||||
},
|
||||
] as MockMethod[];
|
||||
|
123
package.json
123
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vben-admin",
|
||||
"version": "2.5.0",
|
||||
"version": "2.6.1",
|
||||
"author": {
|
||||
"name": "vben",
|
||||
"email": "anncwb@126.com",
|
||||
@@ -10,7 +10,8 @@
|
||||
"bootstrap": "yarn install",
|
||||
"serve": "npm run dev",
|
||||
"dev": "vite",
|
||||
"build": "vite build && esno ./build/script/postBuild.ts",
|
||||
"build": "cross-env NODE_ENV=production vite build && esno ./build/script/postBuild.ts",
|
||||
"build:test": "cross-env vite build --mode test && esno ./build/script/postBuild.ts",
|
||||
"build:no-cache": "yarn clean:cache && npm run build",
|
||||
"report": "cross-env REPORT=true npm run build",
|
||||
"type:check": "vue-tsc --noEmit --skipLibCheck",
|
||||
@@ -20,7 +21,7 @@
|
||||
"clean:cache": "rimraf node_modules/.cache/ && rimraf node_modules/.vite",
|
||||
"clean:lib": "rimraf node_modules",
|
||||
"lint:eslint": "eslint --cache --max-warnings 0 \"{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 \"src/**/*.{js,json,tsx,css,less,scss,vue,html,md}\"",
|
||||
"lint:stylelint": "stylelint --cache --fix \"**/*.{vue,less,postcss,css,scss}\" --cache --cache-location node_modules/.cache/stylelint/",
|
||||
"lint:lint-staged": "lint-staged -c ./.husky/lintstagedrc.js",
|
||||
"lint:pretty": "pretty-quick --staged",
|
||||
@@ -29,19 +30,18 @@
|
||||
"test:gzip": "http-server dist --cors --gzip -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",
|
||||
"install:husky": "is-ci || husky install",
|
||||
"gen:icon": "esno ./build/generate/icon/index.ts",
|
||||
"postinstall": "npm run install:husky"
|
||||
"prepare": "husky install",
|
||||
"gen:icon": "esno ./build/generate/icon/index.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@iconify/iconify": "^2.0.2",
|
||||
"@logicflow/core": "^0.5.0",
|
||||
"@logicflow/extension": "^0.5.0",
|
||||
"@vueuse/core": "^5.0.3",
|
||||
"@zxcvbn-ts/core": "^0.3.0",
|
||||
"ant-design-vue": "2.1.6",
|
||||
"@iconify/iconify": "^2.0.3",
|
||||
"@logicflow/core": "^0.6.1",
|
||||
"@logicflow/extension": "^0.6.1",
|
||||
"@vueuse/core": "^5.1.4",
|
||||
"@zxcvbn-ts/core": "^1.0.0-beta.0",
|
||||
"ant-design-vue": "2.2.2",
|
||||
"axios": "^0.21.1",
|
||||
"codemirror": "^5.61.1",
|
||||
"codemirror": "^5.62.0",
|
||||
"cropperjs": "^1.5.12",
|
||||
"crypto-js": "^4.0.0",
|
||||
"echarts": "^5.1.2",
|
||||
@@ -50,95 +50,96 @@
|
||||
"mockjs": "^1.1.0",
|
||||
"nprogress": "^0.2.0",
|
||||
"path-to-regexp": "^6.2.0",
|
||||
"pinia": "2.0.0-beta.3",
|
||||
"pinia": "^2.0.0-beta.5",
|
||||
"print-js": "^1.6.0",
|
||||
"qrcode": "^1.4.4",
|
||||
"sortablejs": "^1.13.0",
|
||||
"tinymce": "^5.8.1",
|
||||
"vditor": "^3.8.5",
|
||||
"vue": "3.0.11",
|
||||
"resize-observer-polyfill": "^1.5.1",
|
||||
"sortablejs": "^1.14.0",
|
||||
"tinymce": "^5.8.2",
|
||||
"vditor": "^3.8.6",
|
||||
"vue": "3.1.5",
|
||||
"vue-i18n": "9.1.6",
|
||||
"vue-json-pretty": "^2.0.2",
|
||||
"vue-router": "^4.0.9",
|
||||
"vue-types": "^3.0.2",
|
||||
"vue-router": "^4.0.10",
|
||||
"vue-types": "^4.0.0",
|
||||
"xlsx": "^0.17.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@commitlint/cli": "^12.1.4",
|
||||
"@commitlint/config-conventional": "^12.1.4",
|
||||
"@iconify/json": "^1.1.358",
|
||||
"@iconify/json": "^1.1.374",
|
||||
"@purge-icons/generated": "^0.7.0",
|
||||
"@types/codemirror": "^5.60.0",
|
||||
"@types/crypto-js": "^4.0.1",
|
||||
"@types/fs-extra": "^9.0.11",
|
||||
"@types/inquirer": "^7.3.2",
|
||||
"@types/intro.js": "^3.0.1",
|
||||
"@types/jest": "^26.0.23",
|
||||
"@types/codemirror": "^5.60.2",
|
||||
"@types/crypto-js": "^4.0.2",
|
||||
"@types/fs-extra": "^9.0.12",
|
||||
"@types/inquirer": "^7.3.3",
|
||||
"@types/intro.js": "^3.0.2",
|
||||
"@types/jest": "^26.0.24",
|
||||
"@types/lodash-es": "^4.17.4",
|
||||
"@types/mockjs": "^1.0.3",
|
||||
"@types/node": "^15.12.4",
|
||||
"@types/mockjs": "^1.0.4",
|
||||
"@types/node": "^16.3.3",
|
||||
"@types/nprogress": "^0.2.0",
|
||||
"@types/qrcode": "^1.4.0",
|
||||
"@types/qs": "^6.9.6",
|
||||
"@types/sortablejs": "^1.10.6",
|
||||
"@typescript-eslint/eslint-plugin": "^4.27.0",
|
||||
"@typescript-eslint/parser": "^4.27.0",
|
||||
"@vitejs/plugin-legacy": "^1.4.1",
|
||||
"@vitejs/plugin-vue": "^1.2.3",
|
||||
"@vitejs/plugin-vue-jsx": "^1.1.5",
|
||||
"@vue/compiler-sfc": "3.0.11",
|
||||
"@vue/test-utils": "^2.0.0-rc.7",
|
||||
"autoprefixer": "^10.2.6",
|
||||
"@types/qrcode": "^1.4.1",
|
||||
"@types/qs": "^6.9.7",
|
||||
"@types/sortablejs": "^1.10.7",
|
||||
"@typescript-eslint/eslint-plugin": "^4.28.3",
|
||||
"@typescript-eslint/parser": "^4.28.3",
|
||||
"@vitejs/plugin-legacy": "^1.4.4",
|
||||
"@vitejs/plugin-vue": "^1.2.5",
|
||||
"@vitejs/plugin-vue-jsx": "^1.1.6",
|
||||
"@vue/compiler-sfc": "3.1.5",
|
||||
"@vue/test-utils": "^2.0.0-rc.10",
|
||||
"autoprefixer": "^10.3.1",
|
||||
"commitizen": "^4.2.4",
|
||||
"conventional-changelog-cli": "^2.1.1",
|
||||
"cross-env": "^7.0.3",
|
||||
"dotenv": "^10.0.0",
|
||||
"eslint": "^7.29.0",
|
||||
"eslint": "^7.31.0",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-define-config": "^1.0.8",
|
||||
"eslint-define-config": "^1.0.9",
|
||||
"eslint-plugin-jest": "^24.3.6",
|
||||
"eslint-plugin-prettier": "^3.4.0",
|
||||
"eslint-plugin-vue": "^7.11.1",
|
||||
"eslint-plugin-vue": "^7.14.0",
|
||||
"esno": "^0.7.3",
|
||||
"fs-extra": "^10.0.0",
|
||||
"http-server": "^0.12.3",
|
||||
"husky": "^6.0.0",
|
||||
"inquirer": "^8.1.1",
|
||||
"husky": "^7.0.1",
|
||||
"inquirer": "^8.1.2",
|
||||
"is-ci": "^3.0.0",
|
||||
"jest": "^27.0.4",
|
||||
"jest": "^27.0.6",
|
||||
"less": "^4.1.1",
|
||||
"lint-staged": "^11.0.0",
|
||||
"lint-staged": "^11.0.1",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"postcss": "^8.3.5",
|
||||
"prettier": "^2.3.1",
|
||||
"prettier": "^2.3.2",
|
||||
"pretty-quick": "^3.1.1",
|
||||
"rimraf": "^3.0.2",
|
||||
"rollup-plugin-visualizer": "5.5.0",
|
||||
"rollup-plugin-visualizer": "5.5.2",
|
||||
"stylelint": "^13.13.1",
|
||||
"stylelint-config-prettier": "^8.0.2",
|
||||
"stylelint-config-standard": "^22.0.0",
|
||||
"stylelint-order": "^4.1.0",
|
||||
"tailwindcss": "^2.2.2",
|
||||
"tailwindcss": "^2.2.4",
|
||||
"ts-jest": "^27.0.3",
|
||||
"ts-node": "^10.0.0",
|
||||
"typescript": "4.3.4",
|
||||
"vite": "2.3.8",
|
||||
"vite-plugin-compression": "^0.2.5",
|
||||
"ts-node": "^10.1.0",
|
||||
"typescript": "4.3.5",
|
||||
"vite": "2.3.6",
|
||||
"vite-plugin-compression": "^0.3.1",
|
||||
"vite-plugin-html": "^2.0.7",
|
||||
"vite-plugin-imagemin": "^0.3.2",
|
||||
"vite-plugin-mock": "^2.8.0",
|
||||
"vite-plugin-imagemin": "^0.4.1",
|
||||
"vite-plugin-mock": "^2.9.3",
|
||||
"vite-plugin-purge-icons": "^0.7.0",
|
||||
"vite-plugin-pwa": "^0.8.1",
|
||||
"vite-plugin-style-import": "^1.0.0",
|
||||
"vite-plugin-svg-icons": "^0.7.1",
|
||||
"vite-plugin-style-import": "^1.0.1",
|
||||
"vite-plugin-svg-icons": "^1.0.1",
|
||||
"vite-plugin-theme": "^0.8.1",
|
||||
"vue-eslint-parser": "^7.6.0",
|
||||
"vue-tsc": "^0.1.7"
|
||||
"vue-eslint-parser": "^7.9.0",
|
||||
"vue-tsc": "^0.2.1"
|
||||
},
|
||||
"resolutions": {
|
||||
"//": "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",
|
||||
"rollup": "^2.52.1"
|
||||
"rollup": "^2.53.2"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@@ -15,6 +15,6 @@ module.exports = {
|
||||
requirePragma: false,
|
||||
proseWrap: 'never',
|
||||
htmlWhitespaceSensitivity: 'strict',
|
||||
endOfLine: 'lf',
|
||||
endOfLine: 'auto',
|
||||
rangeStart: 0,
|
||||
};
|
||||
|
@@ -10,7 +10,6 @@
|
||||
import { defineComponent } from 'vue';
|
||||
import { ConfigProvider } from 'ant-design-vue';
|
||||
import { AppProvider } from '/@/components/Application';
|
||||
|
||||
import { useTitle } from '/@/hooks/web/useTitle';
|
||||
import { useLocale } from '/@/locales/useLocale';
|
||||
|
||||
|
@@ -8,4 +8,4 @@ enum Api {
|
||||
* @description: Get sample options value
|
||||
*/
|
||||
export const optionsListApi = (params?: selectParams) =>
|
||||
defHttp.post<DemoOptionsItem[]>({ url: Api.OPTIONS_LIST, params });
|
||||
defHttp.get<DemoOptionsItem[]>({ url: Api.OPTIONS_LIST, params });
|
||||
|
11
src/api/demo/tree.ts
Normal file
11
src/api/demo/tree.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
|
||||
enum Api {
|
||||
TREE_OPTIONS_LIST = '/tree/getDemoOptions',
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: Get sample options value
|
||||
*/
|
||||
export const treeOptionsListApi = (params?: Recordable) =>
|
||||
defHttp.get<Recordable[]>({ url: Api.TREE_OPTIONS_LIST, params });
|
@@ -5,6 +5,7 @@ import { ErrorMessageMode } from '/#/axios';
|
||||
|
||||
enum Api {
|
||||
Login = '/login',
|
||||
Logout = '/logout',
|
||||
GetUserInfo = '/getUserInfo',
|
||||
GetPermCode = '/getPermCode',
|
||||
}
|
||||
@@ -34,3 +35,7 @@ export function getUserInfo() {
|
||||
export function getPermCode() {
|
||||
return defHttp.get<string[]>({ url: Api.GetPermCode });
|
||||
}
|
||||
|
||||
export function doLogout() {
|
||||
return defHttp.get({ url: Api.Logout });
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<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"/>
|
||||
<rect 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="#2c41b4"/>
|
||||
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.3 KiB |
@@ -17,6 +17,7 @@
|
||||
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { PageEnum } from '/@/enums/pageEnum';
|
||||
import { useUserStore } from '/@/store/modules/user';
|
||||
|
||||
const props = {
|
||||
/**
|
||||
@@ -39,6 +40,7 @@
|
||||
setup(props) {
|
||||
const { prefixCls } = useDesign('app-logo');
|
||||
const { getCollapsedShowTitle } = useMenuSetting();
|
||||
const userStore = useUserStore();
|
||||
const { title } = useGlobSetting();
|
||||
const go = useGo();
|
||||
|
||||
@@ -56,7 +58,7 @@
|
||||
]);
|
||||
|
||||
function goHome() {
|
||||
go(PageEnum.BASE_HOME);
|
||||
go(userStore.getUserInfo.homePath || PageEnum.BASE_HOME);
|
||||
}
|
||||
|
||||
return {
|
||||
|
@@ -55,7 +55,7 @@ export function useMenuSearch(refs: Ref<HTMLElement[]>, scrollWrap: Ref<ElRef>,
|
||||
}
|
||||
const reg = createSearchReg(unref(keyword));
|
||||
const filterMenu = filter(menuList, (item) => {
|
||||
return reg.test(item.name);
|
||||
return reg.test(item.name) && !item.hideMenu;
|
||||
});
|
||||
searchResult.value = handlerSearchResult(filterMenu, reg);
|
||||
activeIndex.value = 0;
|
||||
@@ -64,15 +64,15 @@ export function useMenuSearch(refs: Ref<HTMLElement[]>, scrollWrap: Ref<ElRef>,
|
||||
function handlerSearchResult(filterMenu: Menu[], reg: RegExp, parent?: Menu) {
|
||||
const ret: SearchResult[] = [];
|
||||
filterMenu.forEach((item) => {
|
||||
const { name, path, icon, children } = item;
|
||||
if (reg.test(name) && !children?.length) {
|
||||
const { name, path, icon, children, hideMenu, meta } = item;
|
||||
if (!hideMenu && reg.test(name) && (!children?.length || meta?.hideChildrenInMenu)) {
|
||||
ret.push({
|
||||
name: parent?.name ? `${parent.name} > ${name}` : name,
|
||||
path,
|
||||
icon,
|
||||
});
|
||||
}
|
||||
if (Array.isArray(children) && children.length) {
|
||||
if (!meta?.hideChildrenInMenu && Array.isArray(children) && children.length) {
|
||||
ret.push(...handlerSearchResult(children, reg, item));
|
||||
}
|
||||
});
|
||||
|
@@ -1,6 +1,9 @@
|
||||
import { withInstall } from '/@/utils';
|
||||
import type { ExtractPropTypes } from 'vue';
|
||||
import button from './src/BasicButton.vue';
|
||||
import popConfirmButton from './src/PopConfirmButton.vue';
|
||||
import { buttonProps } from './src/props';
|
||||
|
||||
export const Button = withInstall(button);
|
||||
export const PopConfirmButton = withInstall(popConfirmButton);
|
||||
export declare type ButtonProps = Partial<ExtractPropTypes<typeof buttonProps>>;
|
||||
|
@@ -10,33 +10,14 @@
|
||||
<script lang="ts">
|
||||
import { defineComponent, computed } from 'vue';
|
||||
import { Button } from 'ant-design-vue';
|
||||
import { Icon } from '/@/components/Icon';
|
||||
|
||||
const props = {
|
||||
color: { type: String, validator: (v) => ['error', 'warning', 'success', ''].includes(v) },
|
||||
loading: { type: Boolean },
|
||||
disabled: { type: Boolean },
|
||||
/**
|
||||
* Text before icon.
|
||||
*/
|
||||
preIcon: { type: String },
|
||||
/**
|
||||
* Text after icon.
|
||||
*/
|
||||
postIcon: { type: String },
|
||||
/**
|
||||
* preIcon and postIcon icon size.
|
||||
* @default: 14
|
||||
*/
|
||||
iconSize: { type: Number, default: 14 },
|
||||
onClick: { type: Function as PropType<(...args) => any>, default: null },
|
||||
};
|
||||
import Icon from '/@/components/Icon/src/Icon.vue';
|
||||
import { buttonProps } from './props';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'AButton',
|
||||
components: { Button, Icon },
|
||||
inheritAttrs: false,
|
||||
props,
|
||||
props: buttonProps,
|
||||
setup(props, { attrs }) {
|
||||
// get component class
|
||||
const getButtonClass = computed(() => {
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { defineComponent, h, unref, computed } from 'vue';
|
||||
import { computed, defineComponent, h, unref } from 'vue';
|
||||
import BasicButton from './BasicButton.vue';
|
||||
import { Popconfirm } from 'ant-design-vue';
|
||||
import { extendSlots } from '/@/utils/helper/tsxHelper';
|
||||
@@ -29,19 +29,20 @@
|
||||
|
||||
// get inherit binding value
|
||||
const getBindValues = computed(() => {
|
||||
const popValues = Object.assign(
|
||||
return Object.assign(
|
||||
{
|
||||
okText: t('common.okText'),
|
||||
cancelText: t('common.cancelText'),
|
||||
},
|
||||
{ ...props, ...unref(attrs) }
|
||||
);
|
||||
return popValues;
|
||||
});
|
||||
|
||||
return () => {
|
||||
const bindValues = omit(unref(getBindValues), 'icon');
|
||||
const Button = h(BasicButton, bindValues, extendSlots(slots));
|
||||
const btnBind = omit(bindValues, 'title');
|
||||
if (btnBind.disabled) btnBind.color = '';
|
||||
const Button = h(BasicButton, btnBind, extendSlots(slots));
|
||||
|
||||
// If it is not enabled, it is a normal button
|
||||
if (!props.enable) {
|
||||
|
19
src/components/Button/src/props.ts
Normal file
19
src/components/Button/src/props.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
export const buttonProps = {
|
||||
color: { type: String, validator: (v) => ['error', 'warning', 'success', ''].includes(v) },
|
||||
loading: { type: Boolean },
|
||||
disabled: { type: Boolean },
|
||||
/**
|
||||
* Text before icon.
|
||||
*/
|
||||
preIcon: { type: String },
|
||||
/**
|
||||
* Text after icon.
|
||||
*/
|
||||
postIcon: { type: String },
|
||||
/**
|
||||
* preIcon and postIcon icon size.
|
||||
* @default: 14
|
||||
*/
|
||||
iconSize: { type: Number, default: 14 },
|
||||
onClick: { type: Function as PropType<(...args) => any>, default: null },
|
||||
};
|
@@ -29,7 +29,7 @@
|
||||
name: 'CodeEditor',
|
||||
components: { CodeMirrorEditor },
|
||||
props,
|
||||
emits: ['change'],
|
||||
emits: ['change', 'update:value'],
|
||||
setup(props, { emit }) {
|
||||
const getValue = computed(() => {
|
||||
const { value, mode } = props;
|
||||
@@ -42,6 +42,7 @@
|
||||
});
|
||||
|
||||
function handleValueChange(v) {
|
||||
emit('update:value', v);
|
||||
emit('change', v);
|
||||
}
|
||||
|
||||
|
@@ -3,6 +3,9 @@
|
||||
<template #addonAfter>
|
||||
<CountButton :size="size" :count="count" :value="state" :beforeStartFunc="sendCodeApi" />
|
||||
</template>
|
||||
<template #[item]="data" v-for="item in Object.keys($slots).filter((k) => k !== 'addonAfter')">
|
||||
<slot :name="item" v-bind="data"></slot>
|
||||
</template>
|
||||
</a-input>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
|
@@ -84,7 +84,7 @@
|
||||
}
|
||||
|
||||
function formatNumber(num: number | string) {
|
||||
if (!num) {
|
||||
if (!num && num !== 0) {
|
||||
return '';
|
||||
}
|
||||
const { decimals, decimal, separator, suffix, prefix } = props;
|
||||
|
@@ -23,57 +23,80 @@
|
||||
|
||||
<div :class="`${prefixCls}-toolbar`">
|
||||
<Upload :fileList="[]" accept="image/*" :beforeUpload="handleBeforeUpload">
|
||||
<a-button size="small" preIcon="ant-design:upload-outlined" type="primary" />
|
||||
<Tooltip :title="t('component.cropper.selectImage')" placement="bottom">
|
||||
<a-button size="small" preIcon="ant-design:upload-outlined" type="primary" />
|
||||
</Tooltip>
|
||||
</Upload>
|
||||
<Space>
|
||||
<a-button
|
||||
type="primary"
|
||||
preIcon="ant-design:reload-outlined"
|
||||
size="small"
|
||||
@click="handlerToolbar('reset')"
|
||||
/>
|
||||
<a-button
|
||||
type="primary"
|
||||
preIcon="ant-design:rotate-left-outlined"
|
||||
size="small"
|
||||
@click="handlerToolbar('rotate', -45)"
|
||||
/>
|
||||
<a-button
|
||||
type="primary"
|
||||
preIcon="ant-design:rotate-right-outlined"
|
||||
size="small"
|
||||
@click="handlerToolbar('rotate', 45)"
|
||||
/>
|
||||
<a-button
|
||||
type="primary"
|
||||
preIcon="vaadin:arrows-long-h"
|
||||
size="small"
|
||||
@click="handlerToolbar('scaleX')"
|
||||
/>
|
||||
<a-button
|
||||
type="primary"
|
||||
preIcon="vaadin:arrows-long-v"
|
||||
size="small"
|
||||
@click="handlerToolbar('scaleY')"
|
||||
/>
|
||||
<a-button
|
||||
type="primary"
|
||||
preIcon="ant-design:zoom-in-outlined"
|
||||
size="small"
|
||||
@click="handlerToolbar('zoom', 0.1)"
|
||||
/>
|
||||
<a-button
|
||||
type="primary"
|
||||
preIcon="ant-design:zoom-out-outlined"
|
||||
size="small"
|
||||
@click="handlerToolbar('zoom', -0.1)"
|
||||
/>
|
||||
<Tooltip :title="t('component.cropper.btn_reset')" placement="bottom">
|
||||
<a-button
|
||||
type="primary"
|
||||
preIcon="ant-design:reload-outlined"
|
||||
size="small"
|
||||
:disabled="!src"
|
||||
@click="handlerToolbar('reset')"
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip :title="t('component.cropper.btn_rotate_left')" placement="bottom">
|
||||
<a-button
|
||||
type="primary"
|
||||
preIcon="ant-design:rotate-left-outlined"
|
||||
size="small"
|
||||
:disabled="!src"
|
||||
@click="handlerToolbar('rotate', -45)"
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip :title="t('component.cropper.btn_rotate_right')" placement="bottom">
|
||||
<a-button
|
||||
type="primary"
|
||||
preIcon="ant-design:rotate-right-outlined"
|
||||
size="small"
|
||||
:disabled="!src"
|
||||
@click="handlerToolbar('rotate', 45)"
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip :title="t('component.cropper.btn_scale_x')" placement="bottom">
|
||||
<a-button
|
||||
type="primary"
|
||||
preIcon="vaadin:arrows-long-h"
|
||||
size="small"
|
||||
:disabled="!src"
|
||||
@click="handlerToolbar('scaleX')"
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip :title="t('component.cropper.btn_scale_y')" placement="bottom">
|
||||
<a-button
|
||||
type="primary"
|
||||
preIcon="vaadin:arrows-long-v"
|
||||
size="small"
|
||||
:disabled="!src"
|
||||
@click="handlerToolbar('scaleY')"
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip :title="t('component.cropper.btn_zoom_in')" placement="bottom">
|
||||
<a-button
|
||||
type="primary"
|
||||
preIcon="ant-design:zoom-in-outlined"
|
||||
size="small"
|
||||
:disabled="!src"
|
||||
@click="handlerToolbar('zoom', 0.1)"
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip :title="t('component.cropper.btn_zoom_out')" placement="bottom">
|
||||
<a-button
|
||||
type="primary"
|
||||
preIcon="ant-design:zoom-out-outlined"
|
||||
size="small"
|
||||
:disabled="!src"
|
||||
@click="handlerToolbar('zoom', -0.1)"
|
||||
/>
|
||||
</Tooltip>
|
||||
</Space>
|
||||
</div>
|
||||
</div>
|
||||
<div :class="`${prefixCls}-right`">
|
||||
<div :class="`${prefixCls}-preview`">
|
||||
<img :src="previewSource" v-if="previewSource" />
|
||||
<img :src="previewSource" v-if="previewSource" :alt="t('component.cropper.preview')" />
|
||||
</div>
|
||||
<template v-if="previewSource">
|
||||
<div :class="`${prefixCls}-group`">
|
||||
@@ -92,7 +115,7 @@
|
||||
|
||||
import { defineComponent, ref } from 'vue';
|
||||
import CropperImage from './Cropper.vue';
|
||||
import { Space, Upload, Avatar } from 'ant-design-vue';
|
||||
import { Space, Upload, Avatar, Tooltip } from 'ant-design-vue';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||
import { dataURLtoBlob } from '/@/utils/file/base64Conver';
|
||||
@@ -102,13 +125,13 @@
|
||||
const props = {
|
||||
circled: { type: Boolean, default: true },
|
||||
uploadApi: {
|
||||
type: Function as PropType<({ file: Blob, name: stirng, filename: string }) => Promise<any>>,
|
||||
type: Function as PropType<({ file: Blob, name: string, filename: string }) => Promise<any>>,
|
||||
},
|
||||
};
|
||||
|
||||
export default defineComponent({
|
||||
name: 'CropperAvatar',
|
||||
components: { BasicModal, Space, CropperImage, Upload, Avatar },
|
||||
components: { BasicModal, Space, CropperImage, Upload, Avatar, Tooltip },
|
||||
props,
|
||||
emits: ['uploadSuccess', 'register'],
|
||||
setup(props, { emit }) {
|
||||
|
@@ -1,35 +1,70 @@
|
||||
<template>
|
||||
<div :class="getClass" :style="getStyle">
|
||||
<div :class="`${prefixCls}-image-wrapper`" :style="getImageWrapperStyle" @click="openModal">
|
||||
<div :class="`${prefixCls}-image-mask`" :style="getImageWrapperStyle">
|
||||
<Icon
|
||||
icon="ant-design:cloud-upload-outlined"
|
||||
:size="getIconWidth"
|
||||
:style="getImageWrapperStyle"
|
||||
color="#d6d6d6"
|
||||
/>
|
||||
</div>
|
||||
<img :src="sourceValue" v-if="sourceValue" alt="avatar" />
|
||||
</div>
|
||||
<a-button :class="`${prefixCls}-upload-btn`" @click="openModal">
|
||||
{{ t('component.cropper.selectImage') }}
|
||||
<a-button
|
||||
:class="`${prefixCls}-upload-btn`"
|
||||
@click="openModal"
|
||||
v-if="showBtn"
|
||||
v-bind="btnProps"
|
||||
>
|
||||
{{ btnText ? btnText : t('component.cropper.selectImage') }}
|
||||
</a-button>
|
||||
<CopperModal @register="register" @uploadSuccess="handleUploadSuccess" :uploadApi="uploadApi" />
|
||||
|
||||
<CopperModal
|
||||
@register="register"
|
||||
@uploadSuccess="handleUploadSuccess"
|
||||
:uploadApi="uploadApi"
|
||||
:src="sourceValue"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, computed, CSSProperties, unref, ref } from 'vue';
|
||||
import {
|
||||
defineComponent,
|
||||
computed,
|
||||
CSSProperties,
|
||||
unref,
|
||||
ref,
|
||||
watchEffect,
|
||||
watch,
|
||||
PropType,
|
||||
} from 'vue';
|
||||
import CopperModal from './CopperModal.vue';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useModal } from '/@/components/Modal';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import type { ButtonProps } from '/@/components/Button';
|
||||
import Icon from '/@/components/Icon';
|
||||
|
||||
const props = {
|
||||
width: { type: [String, Number], default: '200px' },
|
||||
value: { type: String },
|
||||
showBtn: { type: Boolean, default: true },
|
||||
btnProps: { type: Object as PropType<ButtonProps> },
|
||||
btnText: { type: String, default: '' },
|
||||
uploadApi: { type: Function as PropType<({ file: Blob, name: string }) => Promise<void>> },
|
||||
};
|
||||
|
||||
export default defineComponent({
|
||||
name: 'CropperAvatar',
|
||||
components: { CopperModal },
|
||||
components: { CopperModal, Icon },
|
||||
props,
|
||||
setup(props) {
|
||||
const sourceValue = ref('');
|
||||
emits: ['update:value', 'change'],
|
||||
setup(props, { emit, expose }) {
|
||||
const sourceValue = ref(props.value || '');
|
||||
const { prefixCls } = useDesign('cropper-avatar');
|
||||
const [register, { openModal }] = useModal();
|
||||
const [register, { openModal, closeModal }] = useModal();
|
||||
const { createMessage } = useMessage();
|
||||
const { t } = useI18n();
|
||||
|
||||
@@ -37,22 +72,39 @@
|
||||
|
||||
const getWidth = computed(() => `${props.width}`.replace(/px/, '') + 'px');
|
||||
|
||||
const getIconWidth = computed(() => parseInt(`${props.width}`.replace(/px/, '')) / 2 + 'px');
|
||||
|
||||
const getStyle = computed((): CSSProperties => ({ width: unref(getWidth) }));
|
||||
|
||||
const getImageWrapperStyle = computed(
|
||||
(): CSSProperties => ({ width: unref(getWidth), height: unref(getWidth) })
|
||||
);
|
||||
|
||||
watchEffect(() => {
|
||||
sourceValue.value = props.value || '';
|
||||
});
|
||||
|
||||
watch(
|
||||
() => sourceValue.value,
|
||||
(v: string) => {
|
||||
emit('update:value', v);
|
||||
}
|
||||
);
|
||||
|
||||
function handleUploadSuccess({ source }) {
|
||||
sourceValue.value = source;
|
||||
emit('change', source);
|
||||
createMessage.success(t('component.cropper.uploadSuccess'));
|
||||
}
|
||||
|
||||
expose({ openModal: openModal.bind(null, true), closeModal });
|
||||
|
||||
return {
|
||||
t,
|
||||
prefixCls,
|
||||
register,
|
||||
openModal,
|
||||
getIconWidth,
|
||||
sourceValue,
|
||||
getClass,
|
||||
getImageWrapperStyle,
|
||||
@@ -82,6 +134,27 @@
|
||||
}
|
||||
}
|
||||
|
||||
&-image-mask {
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
width: inherit;
|
||||
height: inherit;
|
||||
border-radius: inherit;
|
||||
border: inherit;
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
cursor: pointer;
|
||||
-webkit-transition: opacity 0.4s;
|
||||
transition: opacity 0.4s;
|
||||
|
||||
::v-deep(svg) {
|
||||
margin: auto;
|
||||
}
|
||||
}
|
||||
|
||||
&-image-mask:hover {
|
||||
opacity: 40;
|
||||
}
|
||||
|
||||
&-upload-btn {
|
||||
margin: 10px auto;
|
||||
}
|
||||
|
@@ -37,7 +37,6 @@
|
||||
defineComponent,
|
||||
ref,
|
||||
computed,
|
||||
watchEffect,
|
||||
watch,
|
||||
unref,
|
||||
nextTick,
|
||||
@@ -135,9 +134,13 @@
|
||||
return !!unref(getProps)?.loading;
|
||||
});
|
||||
|
||||
watchEffect(() => {
|
||||
visibleRef.value = props.visible;
|
||||
});
|
||||
watch(
|
||||
() => props.visible,
|
||||
(newVal, oldVal) => {
|
||||
if (newVal !== oldVal) visibleRef.value = newVal;
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
watch(
|
||||
() => visibleRef.value,
|
||||
|
@@ -11,9 +11,17 @@
|
||||
@click="handleClickMenu(item)"
|
||||
:disabled="item.disabled"
|
||||
>
|
||||
<Popconfirm v-if="popconfirm && item.popConfirm" v-bind="item">
|
||||
<Icon :icon="item.icon" v-if="item.icon" />
|
||||
<span class="ml-1">{{ item.text }}</span>
|
||||
<Popconfirm
|
||||
v-if="popconfirm && item.popConfirm"
|
||||
v-bind="getPopConfirmAttrs(item.popConfirm)"
|
||||
>
|
||||
<template #icon v-if="item.popConfirm.icon">
|
||||
<Icon :icon="item.popConfirm.icon" />
|
||||
</template>
|
||||
<div>
|
||||
<Icon :icon="item.icon" v-if="item.icon" />
|
||||
<span class="ml-1">{{ item.text }}</span>
|
||||
</div>
|
||||
</Popconfirm>
|
||||
<template v-else>
|
||||
<Icon :icon="item.icon" v-if="item.icon" />
|
||||
@@ -28,12 +36,14 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import type { PropType } from 'vue';
|
||||
import { computed, PropType } from 'vue';
|
||||
import type { DropMenu } from './typing';
|
||||
|
||||
import { defineComponent } from 'vue';
|
||||
import { Dropdown, Menu, Popconfirm } from 'ant-design-vue';
|
||||
import { Icon } from '/@/components/Icon';
|
||||
import { omit } from 'lodash-es';
|
||||
import { isFunction } from '/@/utils/is';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'BasicDropdown',
|
||||
@@ -76,8 +86,20 @@
|
||||
item.onClick?.();
|
||||
}
|
||||
|
||||
const getPopConfirmAttrs = computed(() => {
|
||||
return (attrs) => {
|
||||
const originAttrs = omit(attrs, ['confirm', 'cancel', 'icon']);
|
||||
if (!attrs.onConfirm && attrs.confirm && isFunction(attrs.confirm))
|
||||
originAttrs['onConfirm'] = attrs.confirm;
|
||||
if (!attrs.onCancel && attrs.cancel && isFunction(attrs.cancel))
|
||||
originAttrs['onCancel'] = attrs.cancel;
|
||||
return originAttrs;
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
handleClickMenu,
|
||||
getPopConfirmAttrs,
|
||||
getAttr: (key: string | number) => ({ key }),
|
||||
};
|
||||
},
|
||||
|
@@ -8,5 +8,6 @@ export { useForm } from './src/hooks/useForm';
|
||||
|
||||
export { default as ApiSelect } from './src/components/ApiSelect.vue';
|
||||
export { default as RadioButtonGroup } from './src/components/RadioButtonGroup.vue';
|
||||
export { default as ApiTreeSelect } from './src/components/ApiTreeSelect.vue';
|
||||
|
||||
export { BasicForm };
|
||||
|
@@ -229,6 +229,12 @@
|
||||
|
||||
function setFormModel(key: string, value: any) {
|
||||
formModel[key] = value;
|
||||
const { validateTrigger } = unref(getBindValue);
|
||||
if (!validateTrigger || validateTrigger === 'change') {
|
||||
try {
|
||||
validateFields([key]);
|
||||
} catch (e) {}
|
||||
}
|
||||
}
|
||||
|
||||
function handleEnterPress(e: KeyboardEvent) {
|
||||
|
@@ -22,6 +22,7 @@ import {
|
||||
|
||||
import RadioButtonGroup from './components/RadioButtonGroup.vue';
|
||||
import ApiSelect from './components/ApiSelect.vue';
|
||||
import ApiTreeSelect from './components/ApiTreeSelect.vue';
|
||||
import { BasicUpload } from '/@/components/Upload';
|
||||
import { StrengthMeter } from '/@/components/StrengthMeter';
|
||||
import { IconPicker } from '/@/components/Icon';
|
||||
@@ -40,6 +41,7 @@ componentMap.set('AutoComplete', AutoComplete);
|
||||
componentMap.set('Select', Select);
|
||||
componentMap.set('ApiSelect', ApiSelect);
|
||||
componentMap.set('TreeSelect', TreeSelect);
|
||||
componentMap.set('ApiTreeSelect', ApiTreeSelect);
|
||||
componentMap.set('Switch', Switch);
|
||||
componentMap.set('RadioButtonGroup', RadioButtonGroup);
|
||||
componentMap.set('RadioGroup', Radio.Group);
|
||||
|
@@ -2,6 +2,7 @@
|
||||
<Select
|
||||
@dropdownVisibleChange="handleFetch"
|
||||
v-bind="attrs"
|
||||
@change="handleChange"
|
||||
:options="getOptions"
|
||||
v-model:value="state"
|
||||
>
|
||||
@@ -67,11 +68,12 @@
|
||||
const options = ref<OptionsItem[]>([]);
|
||||
const loading = ref(false);
|
||||
const isFirstLoad = ref(true);
|
||||
const emitData = ref<any[]>([]);
|
||||
const attrs = useAttrs();
|
||||
const { t } = useI18n();
|
||||
|
||||
// Embedded in the form, just use the hook binding to perform form verification
|
||||
const [state] = useRuleFormItem(props);
|
||||
const [state] = useRuleFormItem(props, 'value', 'change', emitData);
|
||||
|
||||
const getOptions = computed(() => {
|
||||
const { labelField, valueField, numberToString } = props;
|
||||
@@ -104,7 +106,7 @@
|
||||
async function fetch() {
|
||||
const api = props.api;
|
||||
if (!api || !isFunction(api)) return;
|
||||
|
||||
options.value = [];
|
||||
try {
|
||||
loading.value = true;
|
||||
const res = await api(props.params);
|
||||
@@ -132,10 +134,14 @@
|
||||
}
|
||||
|
||||
function emitChange() {
|
||||
emit('options-change', unref(options));
|
||||
emit('options-change', unref(getOptions));
|
||||
}
|
||||
|
||||
return { state, attrs, getOptions, loading, t, handleFetch };
|
||||
function handleChange(_, ...args) {
|
||||
emitData.value = args;
|
||||
}
|
||||
|
||||
return { state, attrs, getOptions, loading, t, handleFetch, handleChange };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
85
src/components/Form/src/components/ApiTreeSelect.vue
Normal file
85
src/components/Form/src/components/ApiTreeSelect.vue
Normal file
@@ -0,0 +1,85 @@
|
||||
<template>
|
||||
<a-tree-select v-bind="getAttrs" @change="handleChange">
|
||||
<template #[item]="data" v-for="item in Object.keys($slots)">
|
||||
<slot :name="item" v-bind="data"></slot>
|
||||
</template>
|
||||
<template #suffixIcon v-if="loading">
|
||||
<LoadingOutlined spin />
|
||||
</template>
|
||||
</a-tree-select>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, watch, ref, onMounted, unref } from 'vue';
|
||||
import { TreeSelect } from 'ant-design-vue';
|
||||
import { isArray, isFunction } from '/@/utils/is';
|
||||
import { get } from 'lodash-es';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
import { LoadingOutlined } from '@ant-design/icons-vue';
|
||||
export default defineComponent({
|
||||
name: 'ApiTreeSelect',
|
||||
components: { ATreeSelect: TreeSelect, LoadingOutlined },
|
||||
props: {
|
||||
api: { type: Function as PropType<(arg?: Recordable) => Promise<Recordable>> },
|
||||
params: { type: Object },
|
||||
immediate: { type: Boolean, default: true },
|
||||
resultField: propTypes.string.def(''),
|
||||
},
|
||||
emits: ['options-change', 'change'],
|
||||
setup(props, { attrs, emit }) {
|
||||
const treeData = ref<Recordable[]>([]);
|
||||
const isFirstLoaded = ref<Boolean>(false);
|
||||
const loading = ref(false);
|
||||
const getAttrs = computed(() => {
|
||||
return {
|
||||
...(props.api ? { treeData: unref(treeData) } : {}),
|
||||
...attrs,
|
||||
};
|
||||
});
|
||||
|
||||
function handleChange(...args) {
|
||||
emit('change', ...args);
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.params,
|
||||
() => {
|
||||
isFirstLoaded.value && fetch();
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.immediate,
|
||||
(v) => {
|
||||
v && !isFirstLoaded.value && fetch();
|
||||
}
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
props.immediate && fetch();
|
||||
});
|
||||
|
||||
async function fetch() {
|
||||
const { api } = props;
|
||||
if (!api || !isFunction(api)) return;
|
||||
loading.value = true;
|
||||
treeData.value = [];
|
||||
let result;
|
||||
try {
|
||||
result = await api(props.params);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
loading.value = false;
|
||||
if (!result) return;
|
||||
if (!isArray(result)) {
|
||||
result = get(result, props.resultField);
|
||||
}
|
||||
treeData.value = (result as Recordable[]) || [];
|
||||
isFirstLoaded.value = true;
|
||||
emit('options-change', treeData.value);
|
||||
}
|
||||
return { getAttrs, loading, handleChange };
|
||||
},
|
||||
});
|
||||
</script>
|
@@ -1,49 +1,51 @@
|
||||
<template>
|
||||
<a-col v-bind="actionColOpt" :style="{ textAlign: 'right' }" v-if="showActionButtonGroup">
|
||||
<FormItem>
|
||||
<slot name="resetBefore"></slot>
|
||||
<Button
|
||||
type="default"
|
||||
class="mr-2"
|
||||
v-bind="getResetBtnOptions"
|
||||
@click="resetAction"
|
||||
v-if="showResetButton"
|
||||
>
|
||||
{{ getResetBtnOptions.text }}
|
||||
</Button>
|
||||
<slot name="submitBefore"></slot>
|
||||
<div style="width: 100%; text-align: right">
|
||||
<FormItem>
|
||||
<slot name="resetBefore"></slot>
|
||||
<Button
|
||||
type="default"
|
||||
class="mr-2"
|
||||
v-bind="getResetBtnOptions"
|
||||
@click="resetAction"
|
||||
v-if="showResetButton"
|
||||
>
|
||||
{{ getResetBtnOptions.text }}
|
||||
</Button>
|
||||
<slot name="submitBefore"></slot>
|
||||
|
||||
<Button
|
||||
type="primary"
|
||||
class="mr-2"
|
||||
v-bind="getSubmitBtnOptions"
|
||||
@click="submitAction"
|
||||
v-if="showSubmitButton"
|
||||
>
|
||||
{{ getSubmitBtnOptions.text }}
|
||||
</Button>
|
||||
<Button
|
||||
type="primary"
|
||||
class="mr-2"
|
||||
v-bind="getSubmitBtnOptions"
|
||||
@click="submitAction"
|
||||
v-if="showSubmitButton"
|
||||
>
|
||||
{{ getSubmitBtnOptions.text }}
|
||||
</Button>
|
||||
|
||||
<slot name="advanceBefore"></slot>
|
||||
<Button
|
||||
type="link"
|
||||
size="small"
|
||||
@click="toggleAdvanced"
|
||||
v-if="showAdvancedButton && !hideAdvanceBtn"
|
||||
>
|
||||
{{ isAdvanced ? t('component.form.putAway') : t('component.form.unfold') }}
|
||||
<BasicArrow class="ml-1" :expand="!isAdvanced" up />
|
||||
</Button>
|
||||
<slot name="advanceAfter"></slot>
|
||||
</FormItem>
|
||||
<slot name="advanceBefore"></slot>
|
||||
<Button
|
||||
type="link"
|
||||
size="small"
|
||||
@click="toggleAdvanced"
|
||||
v-if="showAdvancedButton && !hideAdvanceBtn"
|
||||
>
|
||||
{{ isAdvanced ? t('component.form.putAway') : t('component.form.unfold') }}
|
||||
<BasicArrow class="ml-1" :expand="!isAdvanced" up />
|
||||
</Button>
|
||||
<slot name="advanceAfter"></slot>
|
||||
</FormItem>
|
||||
</div>
|
||||
</a-col>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import type { ColEx } from '../types/index';
|
||||
import type { ButtonProps } from 'ant-design-vue/es/button/buttonTypes';
|
||||
//import type { ButtonProps } from 'ant-design-vue/es/button/buttonTypes';
|
||||
import { defineComponent, computed, PropType } from 'vue';
|
||||
import { Form, Col } from 'ant-design-vue';
|
||||
import { Button } from '/@/components/Button';
|
||||
import { BasicArrow } from '/@/components/Basic/index';
|
||||
import { Button, ButtonProps } from '/@/components/Button';
|
||||
import { BasicArrow } from '/@/components/Basic';
|
||||
import { useFormContext } from '../hooks/useFormContext';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
|
@@ -326,10 +326,10 @@
|
||||
labelCol={labelCol}
|
||||
wrapperCol={wrapperCol}
|
||||
>
|
||||
<>
|
||||
{getContent()}
|
||||
<div style="display:flex">
|
||||
<div style="flex:1">{getContent()}</div>
|
||||
{showSuffix && <span class="suffix">{getSuffix}</span>}
|
||||
</>
|
||||
</div>
|
||||
</Form.Item>
|
||||
);
|
||||
}
|
||||
|
@@ -26,7 +26,7 @@ export function useFormValues({
|
||||
for (const item of Object.entries(values)) {
|
||||
let [, value] = item;
|
||||
const [key] = item;
|
||||
if ((isArray(value) && value.length === 0) || isFunction(value)) {
|
||||
if (!key || (isArray(value) && value.length === 0) || isFunction(value)) {
|
||||
continue;
|
||||
}
|
||||
const transformDateFunc = unref(getProps).transformDateFunc;
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import type { NamePath, RuleObject } from 'ant-design-vue/lib/form/interface';
|
||||
import type { VNode } from 'vue';
|
||||
import type { ButtonProps as AntdButtonProps } from 'ant-design-vue/es/button/buttonTypes';
|
||||
import type { ButtonProps as AntdButtonProps } from '/@/components/Button';
|
||||
import type { FormItem } from './formItem';
|
||||
import type { ColEx, ComponentType } from './index';
|
||||
import type { TableActionType } from '/@/components/Table/src/types/table';
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import type { NamePath } from 'ant-design-vue/lib/form/interface';
|
||||
import type { ColProps } from 'ant-design-vue/lib/grid/Col';
|
||||
import type { VNodeChild } from 'vue';
|
||||
import type { HTMLAttributes, VNodeChild } from 'vue';
|
||||
|
||||
export interface FormItem {
|
||||
/**
|
||||
@@ -39,7 +39,7 @@ export interface FormItem {
|
||||
* The layout of label. You can set span offset to something like {span: 3, offset: 12} or sm: {span: 3, offset: 12} same as with <Col>
|
||||
* @type Col
|
||||
*/
|
||||
labelCol?: ColProps;
|
||||
labelCol?: ColProps & HTMLAttributes;
|
||||
|
||||
/**
|
||||
* Whether provided or not, it will be generated by the validation rule.
|
||||
|
@@ -91,6 +91,7 @@ export type ComponentType =
|
||||
| 'Select'
|
||||
| 'ApiSelect'
|
||||
| 'TreeSelect'
|
||||
| 'ApiTreeSelect'
|
||||
| 'RadioButtonGroup'
|
||||
| 'RadioGroup'
|
||||
| 'Checkbox'
|
||||
|
@@ -1,5 +1,11 @@
|
||||
<template>
|
||||
<SvgIcon :size="size" :name="getSvgIcon" v-if="isSvgIcon" :class="[$attrs.class]" :spin="spin" />
|
||||
<SvgIcon
|
||||
:size="size"
|
||||
:name="getSvgIcon"
|
||||
v-if="isSvgIcon"
|
||||
:class="[$attrs.class, 'anticon']"
|
||||
:spin="spin"
|
||||
/>
|
||||
<span
|
||||
v-else
|
||||
ref="elRef"
|
||||
@@ -19,7 +25,6 @@
|
||||
computed,
|
||||
CSSProperties,
|
||||
} from 'vue';
|
||||
|
||||
import SvgIcon from './SvgIcon.vue';
|
||||
import Iconify from '@purge-icons/generated';
|
||||
import { isString } from '/@/utils/is';
|
||||
@@ -27,7 +32,7 @@
|
||||
|
||||
const SVG_END_WITH_FLAG = '|svg';
|
||||
export default defineComponent({
|
||||
name: 'GIcon',
|
||||
name: 'Icon',
|
||||
components: { SvgIcon },
|
||||
props: {
|
||||
// icon name
|
||||
|
@@ -5,18 +5,19 @@
|
||||
import {
|
||||
defineComponent,
|
||||
ref,
|
||||
onMounted,
|
||||
unref,
|
||||
onUnmounted,
|
||||
nextTick,
|
||||
computed,
|
||||
watch,
|
||||
onBeforeUnmount,
|
||||
onDeactivated,
|
||||
} from 'vue';
|
||||
import Vditor from 'vditor';
|
||||
import 'vditor/dist/index.css';
|
||||
import { useLocale } from '/@/locales/useLocale';
|
||||
import { useModalContext } from '../../Modal';
|
||||
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
|
||||
import { onMountedOrActivated } from '/@/hooks/core/onMountedOrActivated';
|
||||
|
||||
type Lang = 'zh_CN' | 'en_US' | 'ja_JP' | 'ko_KR' | undefined;
|
||||
|
||||
@@ -26,7 +27,7 @@
|
||||
height: { type: Number, default: 360 },
|
||||
value: { type: String, default: '' },
|
||||
},
|
||||
emits: ['change', 'get'],
|
||||
emits: ['change', 'get', 'update:value'],
|
||||
setup(props, { attrs, emit }) {
|
||||
const wrapRef = ref<ElRef>(null);
|
||||
const vditorRef = ref<Nullable<Vditor>>(null);
|
||||
@@ -36,17 +37,16 @@
|
||||
|
||||
const { getLocale } = useLocale();
|
||||
const { getDarkMode } = useRootSetting();
|
||||
const valueRef = ref('');
|
||||
|
||||
watch(
|
||||
[() => getDarkMode.value, () => initedRef.value],
|
||||
([val]) => {
|
||||
const vditor = unref(vditorRef);
|
||||
|
||||
if (!vditor) {
|
||||
([val, inited]) => {
|
||||
if (!inited) {
|
||||
return;
|
||||
}
|
||||
const theme = val === 'dark' ? 'dark' : undefined;
|
||||
vditor.setTheme(theme as 'dark');
|
||||
const theme = val === 'dark' ? 'dark' : 'classic';
|
||||
instance.getVditor()?.setTheme(theme);
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
@@ -54,6 +54,16 @@
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.value,
|
||||
(v) => {
|
||||
if (v !== valueRef.value) {
|
||||
instance.getVditor()?.setValue(v);
|
||||
}
|
||||
valueRef.value = v;
|
||||
}
|
||||
);
|
||||
|
||||
const getCurrentLang = computed((): 'zh_CN' | 'en_US' | 'ja_JP' | 'ko_KR' => {
|
||||
let lang: Lang;
|
||||
switch (unref(getLocale)) {
|
||||
@@ -72,54 +82,58 @@
|
||||
return lang;
|
||||
});
|
||||
function init() {
|
||||
const wrapEl = unref(wrapRef);
|
||||
const wrapEl = unref(wrapRef) as HTMLElement;
|
||||
if (!wrapEl) return;
|
||||
const bindValue = { ...attrs, ...props };
|
||||
vditorRef.value = new Vditor(wrapEl, {
|
||||
theme: 'classic',
|
||||
const insEditor = new Vditor(wrapEl, {
|
||||
theme: getDarkMode.value === 'dark' ? 'dark' : 'classic',
|
||||
lang: unref(getCurrentLang),
|
||||
mode: 'sv',
|
||||
preview: {
|
||||
actions: [],
|
||||
},
|
||||
input: (v) => {
|
||||
// emit('update:value', v);
|
||||
valueRef.value = v;
|
||||
emit('update:value', v);
|
||||
emit('change', v);
|
||||
},
|
||||
after: () => {
|
||||
nextTick(() => {
|
||||
modalFn?.redoModalHeight?.();
|
||||
insEditor.setValue(valueRef.value);
|
||||
vditorRef.value = insEditor;
|
||||
initedRef.value = true;
|
||||
emit('get', instance);
|
||||
});
|
||||
},
|
||||
blur: () => {
|
||||
unref(vditorRef)?.setValue(props.value);
|
||||
//unref(vditorRef)?.setValue(props.value);
|
||||
},
|
||||
...bindValue,
|
||||
cache: {
|
||||
enable: false,
|
||||
},
|
||||
});
|
||||
initedRef.value = true;
|
||||
}
|
||||
|
||||
const instance = {
|
||||
getVditor: (): Vditor => vditorRef.value!,
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
init();
|
||||
setTimeout(() => {
|
||||
modalFn?.redoModalHeight?.();
|
||||
}, 200);
|
||||
});
|
||||
|
||||
emit('get', instance);
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
function destroy() {
|
||||
const vditorInstance = unref(vditorRef);
|
||||
if (!vditorInstance) return;
|
||||
try {
|
||||
vditorInstance?.destroy?.();
|
||||
} catch (error) {}
|
||||
});
|
||||
vditorRef.value = null;
|
||||
initedRef.value = false;
|
||||
}
|
||||
|
||||
onMountedOrActivated(init);
|
||||
|
||||
onBeforeUnmount(destroy);
|
||||
onDeactivated(destroy);
|
||||
return {
|
||||
wrapRef,
|
||||
...instance,
|
||||
|
@@ -19,25 +19,18 @@
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import type { MenuState } from './types';
|
||||
|
||||
import { computed, defineComponent, unref, reactive, watch, toRefs, ref } from 'vue';
|
||||
import { Menu } from 'ant-design-vue';
|
||||
import BasicSubMenuItem from './components/BasicSubMenuItem.vue';
|
||||
|
||||
import { MenuModeEnum, MenuTypeEnum } from '/@/enums/menuEnum';
|
||||
|
||||
import { useOpenKeys } from './useOpenKeys';
|
||||
import { RouteLocationNormalizedLoaded, useRouter } from 'vue-router';
|
||||
|
||||
import { isFunction } from '/@/utils/is';
|
||||
|
||||
import { basicProps } from './props';
|
||||
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
||||
import { REDIRECT_NAME } from '/@/router/constant';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
|
||||
import { getCurrentParentPath } from '/@/router/menus';
|
||||
|
||||
import { listenerRouteChange } from '/@/logics/mitt/routeChange';
|
||||
import { getAllParentPath } from '/@/router/helper/menuHelper';
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<MenuItem>
|
||||
<MenuItem :key="item.path">
|
||||
<!-- <MenuItem :class="getLevelClass"> -->
|
||||
<MenuItemContent v-bind="$props" :item="item" />
|
||||
</MenuItem>
|
||||
|
@@ -3,6 +3,7 @@
|
||||
<SubMenu
|
||||
v-if="menuHasChildren(item) && getShowMenu"
|
||||
:class="[theme]"
|
||||
:key="`submenu-${item.path}`"
|
||||
popupClassName="app-top-menu-popup"
|
||||
>
|
||||
<template #title>
|
||||
@@ -16,7 +17,6 @@
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import type { Menu as MenuType } from '/@/router/types';
|
||||
|
||||
import { defineComponent, computed } from 'vue';
|
||||
import { Menu } from 'ant-design-vue';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<span :class="`${prefixCls}- flex items-center `">
|
||||
<Icon v-if="getIcon" :icon="getIcon" :size="18" :class="`${prefixCls}-wrapper__icon`" />
|
||||
<Icon v-if="getIcon" :icon="getIcon" :size="18" :class="`${prefixCls}-wrapper__icon mr-2`" />
|
||||
{{ getI18nName }}
|
||||
</span>
|
||||
</template>
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<Modal v-bind="getBindValue">
|
||||
<Modal v-bind="getBindValue" @cancel="handleCancel">
|
||||
<template #closeIcon v-if="!$slots.closeIcon">
|
||||
<ModalClose
|
||||
:canFullscreen="getProps.canFullscreen"
|
||||
@@ -18,7 +18,7 @@
|
||||
</template>
|
||||
|
||||
<template #footer v-if="!$slots.footer">
|
||||
<ModalFooter v-bind="getProps" @ok="handleOk" @cancel="handleCancel">
|
||||
<ModalFooter v-bind="getBindValue" @ok="handleOk" @cancel="handleCancel">
|
||||
<template #[item]="data" v-for="item in Object.keys($slots)">
|
||||
<slot :name="item" v-bind="data"></slot>
|
||||
</template>
|
||||
@@ -82,7 +82,7 @@
|
||||
setup(props, { emit, attrs }) {
|
||||
const visibleRef = ref(false);
|
||||
const propsRef = ref<Partial<ModalProps> | null>(null);
|
||||
const modalWrapperRef = ref<ComponentRef>(null);
|
||||
const modalWrapperRef = ref<any>(null);
|
||||
|
||||
// modal Bottom and top height
|
||||
const extHeightRef = ref(0);
|
||||
@@ -133,7 +133,12 @@
|
||||
});
|
||||
|
||||
const getBindValue = computed((): Recordable => {
|
||||
const attr = { ...attrs, ...unref(getProps) };
|
||||
const attr = {
|
||||
...attrs,
|
||||
...unref(getMergeProps),
|
||||
visible: unref(visibleRef),
|
||||
wrapClassName: unref(getWrapClassName),
|
||||
};
|
||||
if (unref(fullScreenRef)) {
|
||||
return omit(attr, 'height');
|
||||
}
|
||||
@@ -187,8 +192,12 @@
|
||||
function setModalProps(props: Partial<ModalProps>): void {
|
||||
// Keep the last setModalProps
|
||||
propsRef.value = deepMerge(unref(propsRef) || ({} as any), props);
|
||||
if (!Reflect.has(props, 'visible')) return;
|
||||
visibleRef.value = !!props.visible;
|
||||
if (Reflect.has(props, 'visible')) {
|
||||
visibleRef.value = !!props.visible;
|
||||
}
|
||||
if (Reflect.has(props, 'defaultFullscreen')) {
|
||||
fullScreenRef.value = !!props.defaultFullscreen;
|
||||
}
|
||||
}
|
||||
|
||||
function handleOk(e: Event) {
|
||||
|
@@ -1,20 +1,28 @@
|
||||
<template>
|
||||
<div :class="getClass">
|
||||
<template v-if="canFullscreen">
|
||||
<FullscreenExitOutlined role="full" @click="handleFullScreen" v-if="fullScreen" />
|
||||
<FullscreenOutlined role="close" @click="handleFullScreen" v-else />
|
||||
<Tooltip :title="t('component.modal.restore')" placement="bottom" v-if="fullScreen">
|
||||
<FullscreenExitOutlined role="full" @click="handleFullScreen" />
|
||||
</Tooltip>
|
||||
<Tooltip :title="t('component.modal.maximize')" placement="bottom" v-else>
|
||||
<FullscreenOutlined role="close" @click="handleFullScreen" />
|
||||
</Tooltip>
|
||||
</template>
|
||||
<CloseOutlined @click="handleCancel" />
|
||||
<Tooltip :title="t('component.modal.close')" placement="bottom">
|
||||
<CloseOutlined @click="handleCancel" />
|
||||
</Tooltip>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, computed } from 'vue';
|
||||
import { FullscreenExitOutlined, FullscreenOutlined, CloseOutlined } from '@ant-design/icons-vue';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { Tooltip } from 'ant-design-vue';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'ModalClose',
|
||||
components: { FullscreenExitOutlined, FullscreenOutlined, CloseOutlined },
|
||||
components: { Tooltip, FullscreenExitOutlined, FullscreenOutlined, CloseOutlined },
|
||||
props: {
|
||||
canFullscreen: { type: Boolean, default: true },
|
||||
fullScreen: { type: Boolean },
|
||||
@@ -22,6 +30,7 @@
|
||||
emits: ['cancel', 'fullscreen'],
|
||||
setup(props, { emit }) {
|
||||
const { prefixCls } = useDesign('basic-modal-close');
|
||||
const { t } = useI18n();
|
||||
|
||||
const getClass = computed(() => {
|
||||
return [
|
||||
@@ -44,6 +53,7 @@
|
||||
}
|
||||
|
||||
return {
|
||||
t,
|
||||
getClass,
|
||||
prefixCls,
|
||||
handleCancel,
|
||||
|
@@ -39,6 +39,7 @@ export interface ModalProps {
|
||||
|
||||
// 是否可以进行全屏
|
||||
canFullscreen?: boolean;
|
||||
defaultFullscreen?: boolean;
|
||||
visible?: boolean;
|
||||
// 温馨提醒信息
|
||||
helpMessage: string | string[];
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div :class="getClass">
|
||||
<div :class="getClass" ref="wrapperRef">
|
||||
<PageHeader
|
||||
:ghost="ghost"
|
||||
:title="title"
|
||||
@@ -18,7 +18,7 @@
|
||||
</template>
|
||||
</PageHeader>
|
||||
|
||||
<div class="overflow-hidden" :class="getContentClass" :style="getContentStyle">
|
||||
<div class="overflow-hidden" :class="getContentClass" :style="getContentStyle" ref="contentRef">
|
||||
<slot></slot>
|
||||
</div>
|
||||
|
||||
@@ -35,16 +35,14 @@
|
||||
<script lang="ts">
|
||||
import type { CSSProperties, PropType } from 'vue';
|
||||
|
||||
import { defineComponent, computed, watch, nextTick, ref, unref } from 'vue';
|
||||
import { defineComponent, computed, watch, ref, unref } from 'vue';
|
||||
import PageFooter from './PageFooter.vue';
|
||||
import { usePageContext } from '/@/hooks/component/usePageContext';
|
||||
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
import { omit } from 'lodash-es';
|
||||
import { PageHeader } from 'ant-design-vue';
|
||||
import { onMountedOrActivated } from '/@/hooks/core/onMountedOrActivated';
|
||||
import { useLayoutHeight } from '/@/layouts/default/content/useContentViewHeight';
|
||||
import { useContentHeight } from '/@/hooks/web/useContentHeight';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'PageWrapper',
|
||||
@@ -64,12 +62,23 @@
|
||||
fixedHeight: propTypes.bool,
|
||||
},
|
||||
setup(props, { slots }) {
|
||||
const headerRef = ref<ComponentRef>(null);
|
||||
const footerRef = ref<ComponentRef>(null);
|
||||
const footerHeight = ref(0);
|
||||
const { prefixCls, prefixVar } = useDesign('page-wrapper');
|
||||
const { contentHeight, setPageHeight, pageHeight } = usePageContext();
|
||||
const { footerHeightRef } = useLayoutHeight();
|
||||
const wrapperRef = ref(null);
|
||||
const headerRef = ref(null);
|
||||
const contentRef = ref(null);
|
||||
const footerRef = ref(null);
|
||||
const { prefixCls } = useDesign('page-wrapper');
|
||||
|
||||
const getIsContentFullHeight = computed(() => {
|
||||
return props.contentFullHeight;
|
||||
});
|
||||
|
||||
const { redoHeight, setCompensation, contentHeight } = useContentHeight(
|
||||
getIsContentFullHeight,
|
||||
wrapperRef,
|
||||
[headerRef, footerRef],
|
||||
[contentRef]
|
||||
);
|
||||
setCompensation({ useLayoutFooter: true, elements: [footerRef] });
|
||||
|
||||
const getClass = computed(() => {
|
||||
return [
|
||||
@@ -91,7 +100,8 @@
|
||||
if (!contentFullHeight) {
|
||||
return { ...contentStyle };
|
||||
}
|
||||
const height = `${unref(pageHeight)}px`;
|
||||
|
||||
const height = `${unref(contentHeight)}px`;
|
||||
return {
|
||||
...contentStyle,
|
||||
minHeight: height,
|
||||
@@ -111,9 +121,9 @@
|
||||
});
|
||||
|
||||
watch(
|
||||
() => [contentHeight?.value, getShowFooter.value, footerHeightRef.value],
|
||||
() => [getShowFooter.value],
|
||||
() => {
|
||||
calcContentHeight();
|
||||
redoHeight();
|
||||
},
|
||||
{
|
||||
flush: 'post',
|
||||
@@ -121,91 +131,16 @@
|
||||
}
|
||||
);
|
||||
|
||||
onMountedOrActivated(() => {
|
||||
nextTick(() => {
|
||||
calcContentHeight();
|
||||
});
|
||||
});
|
||||
|
||||
function calcContentHeight() {
|
||||
if (!props.contentFullHeight) {
|
||||
return;
|
||||
}
|
||||
//fix:in contentHeight mode: delay getting footer and header dom element to get the correct height
|
||||
const footer = unref(footerRef);
|
||||
const header = unref(headerRef);
|
||||
footerHeight.value = 0;
|
||||
const footerEl = footer?.$el;
|
||||
|
||||
if (footerEl) {
|
||||
footerHeight.value += footerEl?.offsetHeight ?? 0;
|
||||
}
|
||||
let headerHeight = 0;
|
||||
const headerEl = header?.$el;
|
||||
if (headerEl) {
|
||||
headerHeight += headerEl?.offsetHeight ?? 0;
|
||||
}
|
||||
// fix:subtract content's marginTop and marginBottom value
|
||||
let subtractHeight = 0;
|
||||
const ZERO_PX = '0px';
|
||||
let marginBottom = ZERO_PX;
|
||||
let marginTop = ZERO_PX;
|
||||
const classElments = document.querySelectorAll(`.${prefixVar}-page-wrapper-content`);
|
||||
if (classElments && classElments.length > 0) {
|
||||
const contentEl = classElments[0];
|
||||
const cssStyle = getComputedStyle(contentEl);
|
||||
marginBottom = cssStyle?.marginBottom ?? ZERO_PX;
|
||||
marginTop = cssStyle?.marginTop ?? ZERO_PX;
|
||||
}
|
||||
if (marginBottom) {
|
||||
const contentMarginBottom = Number(marginBottom.replace(/[^\d]/g, ''));
|
||||
subtractHeight += contentMarginBottom;
|
||||
}
|
||||
if (marginTop) {
|
||||
const contentMarginTop = Number(marginTop.replace(/[^\d]/g, ''));
|
||||
subtractHeight += contentMarginTop;
|
||||
}
|
||||
|
||||
// fix: wrapper marginTop and marginBottom value
|
||||
let wrapperSubtractHeight = 0;
|
||||
let wrapperMarginBottom = ZERO_PX;
|
||||
let wrapperMarginTop = ZERO_PX;
|
||||
const wrapperClassElments = document.querySelectorAll(`.${prefixVar}-page-wrapper`);
|
||||
if (wrapperClassElments && wrapperClassElments.length > 0) {
|
||||
const contentEl = wrapperClassElments[0];
|
||||
const cssStyle = getComputedStyle(contentEl);
|
||||
wrapperMarginBottom = cssStyle?.marginBottom ?? ZERO_PX;
|
||||
wrapperMarginTop = cssStyle?.marginTop ?? ZERO_PX;
|
||||
}
|
||||
if (wrapperMarginBottom) {
|
||||
const contentMarginBottom = Number(wrapperMarginBottom.replace(/[^\d]/g, ''));
|
||||
wrapperSubtractHeight += contentMarginBottom;
|
||||
}
|
||||
if (wrapperMarginTop) {
|
||||
const contentMarginTop = Number(wrapperMarginTop.replace(/[^\d]/g, ''));
|
||||
wrapperSubtractHeight += contentMarginTop;
|
||||
}
|
||||
let height =
|
||||
unref(contentHeight) -
|
||||
unref(footerHeight) -
|
||||
headerHeight -
|
||||
subtractHeight -
|
||||
wrapperSubtractHeight;
|
||||
if (unref(getShowFooter)) {
|
||||
height -= unref(footerHeightRef);
|
||||
}
|
||||
setPageHeight?.(height);
|
||||
}
|
||||
|
||||
return {
|
||||
getContentStyle,
|
||||
footerRef,
|
||||
wrapperRef,
|
||||
headerRef,
|
||||
contentRef,
|
||||
footerRef,
|
||||
getClass,
|
||||
getHeaderSlots,
|
||||
prefixCls,
|
||||
getShowFooter,
|
||||
pageHeight,
|
||||
omit,
|
||||
getContentClass,
|
||||
};
|
||||
|
@@ -21,10 +21,8 @@
|
||||
import type { MenuState } from './types';
|
||||
import type { Menu as MenuType } from '/@/router/types';
|
||||
import type { RouteLocationNormalizedLoaded } from 'vue-router';
|
||||
|
||||
import { defineComponent, computed, ref, unref, reactive, toRefs, watch } from 'vue';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
|
||||
import Menu from './components/Menu.vue';
|
||||
import SimpleSubMenu from './SimpleSubMenu.vue';
|
||||
import { listenerRouteChange } from '/@/logics/mitt/routeChange';
|
||||
@@ -123,6 +121,7 @@
|
||||
return;
|
||||
}
|
||||
const path = (route || unref(currentRoute)).path;
|
||||
|
||||
menuState.activeName = path;
|
||||
|
||||
setOpenKeys(path);
|
||||
|
@@ -9,7 +9,7 @@ import {
|
||||
TimePicker,
|
||||
} from 'ant-design-vue';
|
||||
import type { ComponentType } from './types/componentType';
|
||||
import { ApiSelect } from '/@/components/Form';
|
||||
import { ApiSelect, ApiTreeSelect } from '/@/components/Form';
|
||||
|
||||
const componentMap = new Map<ComponentType, Component>();
|
||||
|
||||
@@ -17,6 +17,7 @@ componentMap.set('Input', Input);
|
||||
componentMap.set('InputNumber', InputNumber);
|
||||
componentMap.set('Select', Select);
|
||||
componentMap.set('ApiSelect', ApiSelect);
|
||||
componentMap.set('ApiTreeSelect', ApiTreeSelect);
|
||||
componentMap.set('Switch', Switch);
|
||||
componentMap.set('Checkbox', Checkbox);
|
||||
componentMap.set('DatePicker', DatePicker);
|
||||
|
@@ -3,11 +3,15 @@ import { BasicArrow } from '/@/components/Basic';
|
||||
export default () => {
|
||||
return (props: Recordable) => {
|
||||
if (!props.expandable) {
|
||||
return <span />;
|
||||
if (props.expanded) {
|
||||
return <span class="ant-table-row-expand-icon ant-table-row-spaced" />;
|
||||
} else {
|
||||
return <span />;
|
||||
}
|
||||
}
|
||||
return (
|
||||
<BasicArrow
|
||||
class="mr-1"
|
||||
style="margin-right: 8px"
|
||||
iconStyle="margin-top: -2px;"
|
||||
onClick={(e: Event) => {
|
||||
props.onExpand(props.record, e);
|
||||
|
@@ -1,9 +1,15 @@
|
||||
<template>
|
||||
<div :class="[prefixCls, getAlign]" @click="onCellClick">
|
||||
<template v-for="(action, index) in getActions" :key="`${index}-${action.label}`">
|
||||
<PopConfirmButton v-bind="action">
|
||||
<Icon :icon="action.icon" class="mr-1" v-if="action.icon" />
|
||||
{{ action.label }}
|
||||
<Tooltip v-if="action.tooltip" v-bind="getTooltip(action.tooltip)">
|
||||
<PopConfirmButton v-bind="action">
|
||||
<Icon :icon="action.icon" :class="{ 'mr-1': !!action.label }" v-if="action.icon" />
|
||||
<template v-if="action.label">{{ action.label }}</template>
|
||||
</PopConfirmButton>
|
||||
</Tooltip>
|
||||
<PopConfirmButton v-else v-bind="action">
|
||||
<Icon :icon="action.icon" :class="{ 'mr-1': !!action.label }" v-if="action.icon" />
|
||||
<template v-if="action.label">{{ action.label }}</template>
|
||||
</PopConfirmButton>
|
||||
<Divider
|
||||
type="vertical"
|
||||
@@ -31,7 +37,7 @@
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType, computed, toRaw } from 'vue';
|
||||
import { MoreOutlined } from '@ant-design/icons-vue';
|
||||
import { Divider } from 'ant-design-vue';
|
||||
import { Divider, Tooltip, TooltipProps } from 'ant-design-vue';
|
||||
import Icon from '/@/components/Icon/index';
|
||||
import { ActionItem, TableActionType } from '/@/components/Table';
|
||||
import { PopConfirmButton } from '/@/components/Button';
|
||||
@@ -39,13 +45,13 @@
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useTableContext } from '../hooks/useTableContext';
|
||||
import { usePermission } from '/@/hooks/web/usePermission';
|
||||
import { isBoolean, isFunction } from '/@/utils/is';
|
||||
import { isBoolean, isFunction, isString } from '/@/utils/is';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
import { ACTION_COLUMN_FLAG } from '../const';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'TableAction',
|
||||
components: { Icon, PopConfirmButton, Divider, Dropdown, MoreOutlined },
|
||||
components: { Icon, PopConfirmButton, Divider, Dropdown, MoreOutlined, Tooltip },
|
||||
props: {
|
||||
actions: {
|
||||
type: Array as PropType<ActionItem[]>,
|
||||
@@ -124,6 +130,14 @@
|
||||
return actionColumn?.align ?? 'left';
|
||||
});
|
||||
|
||||
function getTooltip(data: string | TooltipProps): TooltipProps {
|
||||
if (isString(data)) {
|
||||
return { title: data, placement: 'bottom' };
|
||||
} else {
|
||||
return Object.assign({ placement: 'bottom' }, data);
|
||||
}
|
||||
}
|
||||
|
||||
function onCellClick(e: MouseEvent) {
|
||||
if (!props.stopButtonPropagation) return;
|
||||
const target = e.target as HTMLElement;
|
||||
@@ -132,7 +146,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
return { prefixCls, getActions, getDropdownList, getAlign, onCellClick };
|
||||
return { prefixCls, getActions, getDropdownList, getAlign, onCellClick, getTooltip };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
@@ -168,6 +182,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
button.ant-btn-circle {
|
||||
span {
|
||||
margin: auto !important;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-divider,
|
||||
.ant-divider-vertical {
|
||||
margin: 0 2px;
|
||||
|
@@ -1,16 +1,25 @@
|
||||
<template>
|
||||
<slot name="tableTitle" v-if="$slots.tableTitle"></slot>
|
||||
|
||||
<TableTitle :helpMessage="titleHelpMessage" :title="title" v-if="!$slots.tableTitle && title" />
|
||||
|
||||
<div :class="`${prefixCls}__toolbar`">
|
||||
<slot name="toolbar"></slot>
|
||||
<Divider type="vertical" v-if="$slots.toolbar && showTableSetting" />
|
||||
<TableSetting
|
||||
:setting="tableSetting"
|
||||
v-if="showTableSetting"
|
||||
@columns-change="handleColumnChange"
|
||||
/>
|
||||
<div style="width: 100%">
|
||||
<div v-if="$slots.headerTop" style="margin: 5px">
|
||||
<slot name="headerTop"></slot>
|
||||
</div>
|
||||
<div style="width: 100%; display: flex">
|
||||
<slot name="tableTitle" v-if="$slots.tableTitle"></slot>
|
||||
<TableTitle
|
||||
:helpMessage="titleHelpMessage"
|
||||
:title="title"
|
||||
v-if="!$slots.tableTitle && title"
|
||||
/>
|
||||
<div :class="`${prefixCls}__toolbar`">
|
||||
<slot name="toolbar"></slot>
|
||||
<Divider type="vertical" v-if="$slots.toolbar && showTableSetting" />
|
||||
<TableSetting
|
||||
:setting="tableSetting"
|
||||
v-if="showTableSetting"
|
||||
@columns-change="handleColumnChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
|
@@ -19,7 +19,7 @@ export const CellComponent: FunctionalComponent = (
|
||||
const Comp = componentMap.get(component) as typeof defineComponent;
|
||||
|
||||
const DefaultComp = h(Comp, attrs);
|
||||
if (!rule) {
|
||||
if (!rule || !popoverVisible) {
|
||||
return DefaultComp;
|
||||
}
|
||||
return h(
|
||||
|
@@ -44,6 +44,8 @@
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
import { isString, isBoolean, isFunction, isNumber, isArray } from '/@/utils/is';
|
||||
import { createPlaceholderMessage } from './helper';
|
||||
import { set, omit } from 'lodash-es';
|
||||
import { treeToList } from '/@/utils/helper/treeHelper';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'EditableCell',
|
||||
@@ -107,7 +109,7 @@
|
||||
return {
|
||||
placeholder: createPlaceholderMessage(unref(getComponent)),
|
||||
...apiSelectProps,
|
||||
...compProps,
|
||||
...omit(compProps, 'onChange'),
|
||||
[valueField]: value,
|
||||
};
|
||||
});
|
||||
@@ -153,6 +155,7 @@
|
||||
|
||||
watchEffect(() => {
|
||||
defaultValueRef.value = props.value;
|
||||
currentValueRef.value = props.value;
|
||||
});
|
||||
|
||||
watchEffect(() => {
|
||||
@@ -183,6 +186,8 @@
|
||||
} else if (isString(e) || isBoolean(e) || isNumber(e)) {
|
||||
currentValueRef.value = e;
|
||||
}
|
||||
const onChange = props.column?.editComponentProps?.onChange;
|
||||
if (onChange && isFunction(onChange)) onChange(...arguments);
|
||||
|
||||
table.emit?.('edit-change', {
|
||||
column: props.column,
|
||||
@@ -227,14 +232,16 @@
|
||||
if (!isPass) return false;
|
||||
}
|
||||
|
||||
const { column, index } = props;
|
||||
const { column, index, record } = props;
|
||||
if (!record) return false;
|
||||
const { key, dataIndex } = column;
|
||||
const value = unref(currentValueRef);
|
||||
if (!key || !dataIndex) return;
|
||||
|
||||
const dataKey = (dataIndex || key) as string;
|
||||
|
||||
const record = await table.updateTableData(index, dataKey, value);
|
||||
set(record, dataKey, value);
|
||||
//const record = await table.updateTableData(index, dataKey, value);
|
||||
needEmit && table.emit?.('edit-end', { record, index, key, value });
|
||||
isEdit.value = false;
|
||||
}
|
||||
@@ -249,7 +256,14 @@
|
||||
function handleCancel() {
|
||||
isEdit.value = false;
|
||||
currentValueRef.value = defaultValueRef.value;
|
||||
table.emit?.('edit-cancel', unref(currentValueRef));
|
||||
const { column, index, record } = props;
|
||||
const { key, dataIndex } = column;
|
||||
table.emit?.('edit-cancel', {
|
||||
record,
|
||||
index,
|
||||
key: dataIndex || key,
|
||||
value: unref(currentValueRef),
|
||||
});
|
||||
}
|
||||
|
||||
function onClickOutside() {
|
||||
@@ -263,9 +277,23 @@
|
||||
}
|
||||
}
|
||||
|
||||
// only ApiSelect
|
||||
// only ApiSelect or TreeSelect
|
||||
function handleOptionsChange(options: LabelValueOptions) {
|
||||
optionsRef.value = options;
|
||||
const { replaceFields } = props.column?.editComponentProps ?? {};
|
||||
const component = unref(getComponent);
|
||||
if (component === 'ApiTreeSelect') {
|
||||
const { title = 'title', value = 'value', children = 'children' } = replaceFields || {};
|
||||
let listOptions: Recordable[] = treeToList(options, { children });
|
||||
listOptions = listOptions.map((item) => {
|
||||
return {
|
||||
label: item[title],
|
||||
value: item[value],
|
||||
};
|
||||
});
|
||||
optionsRef.value = listOptions as LabelValueOptions;
|
||||
} else {
|
||||
optionsRef.value = options;
|
||||
}
|
||||
}
|
||||
|
||||
function initCbs(cbs: 'submitCbs' | 'validCbs' | 'cancelCbs', handle: Fn) {
|
||||
|
@@ -113,7 +113,7 @@ export function useDataSource(
|
||||
const getDataSourceRef = computed(() => {
|
||||
const dataSource = unref(dataSourceRef);
|
||||
if (!dataSource || dataSource.length === 0) {
|
||||
return [];
|
||||
return unref(dataSourceRef);
|
||||
}
|
||||
if (unref(getAutoCreateKey)) {
|
||||
const firstItem = dataSource[0];
|
||||
@@ -176,6 +176,7 @@ export function useDataSource(
|
||||
try {
|
||||
setLoading(true);
|
||||
const { pageField, sizeField, listField, totalField } = Object.assign(
|
||||
{},
|
||||
FETCH_SETTING,
|
||||
fetchSetting
|
||||
);
|
||||
@@ -203,7 +204,7 @@ export function useDataSource(
|
||||
...(opt?.filterInfo ?? {}),
|
||||
};
|
||||
if (beforeFetch && isFunction(beforeFetch)) {
|
||||
params = beforeFetch(params) || params;
|
||||
params = (await beforeFetch(params)) || params;
|
||||
}
|
||||
|
||||
const res = await api(params);
|
||||
@@ -225,7 +226,7 @@ export function useDataSource(
|
||||
}
|
||||
|
||||
if (afterFetch && isFunction(afterFetch)) {
|
||||
resultItems = afterFetch(resultItems) || resultItems;
|
||||
resultItems = (await afterFetch(resultItems)) || resultItems;
|
||||
}
|
||||
dataSourceRef.value = resultItems;
|
||||
setPagination({
|
||||
|
@@ -1,6 +1,8 @@
|
||||
import { isFunction } from '/@/utils/is';
|
||||
import type { BasicTableProps, TableRowSelection } from '../types/table';
|
||||
import { computed, ref, unref, ComputedRef, Ref, toRaw } from 'vue';
|
||||
import { computed, ref, unref, ComputedRef, Ref, toRaw, watch, nextTick } from 'vue';
|
||||
import { ROW_KEY } from '../const';
|
||||
import { omit } from 'lodash-es';
|
||||
|
||||
export function useRowSelection(
|
||||
propsRef: ComputedRef<BasicTableProps>,
|
||||
@@ -22,15 +24,35 @@ export function useRowSelection(
|
||||
onChange: (selectedRowKeys: string[], selectedRows: Recordable[]) => {
|
||||
selectedRowKeysRef.value = selectedRowKeys;
|
||||
selectedRowRef.value = selectedRows;
|
||||
emit('selection-change', {
|
||||
keys: selectedRowKeys,
|
||||
rows: selectedRows,
|
||||
});
|
||||
},
|
||||
...(rowSelection === undefined ? {} : rowSelection),
|
||||
...omit(rowSelection === undefined ? {} : rowSelection, ['onChange']),
|
||||
};
|
||||
});
|
||||
|
||||
watch(
|
||||
() => unref(propsRef).rowSelection?.selectedRowKeys,
|
||||
(v: string[]) => {
|
||||
setSelectedRowKeys(v);
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => unref(selectedRowKeysRef),
|
||||
() => {
|
||||
nextTick(() => {
|
||||
const { rowSelection } = unref(propsRef);
|
||||
if (rowSelection) {
|
||||
const { onChange } = rowSelection;
|
||||
if (onChange && isFunction(onChange)) onChange(getSelectRowKeys(), getSelectRows());
|
||||
}
|
||||
emit('selection-change', {
|
||||
keys: getSelectRowKeys(),
|
||||
rows: getSelectRows(),
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
const getAutoCreateKey = computed(() => {
|
||||
return unref(propsRef).autoCreateKey && !unref(propsRef).rowKey;
|
||||
});
|
||||
|
@@ -41,6 +41,11 @@ export function useTableHeader(
|
||||
tableTitle: () => getSlot(slots, 'tableTitle'),
|
||||
}
|
||||
: {}),
|
||||
...(slots.headerTop
|
||||
? {
|
||||
headerTop: () => getSlot(slots, 'headerTop'),
|
||||
}
|
||||
: {}),
|
||||
}
|
||||
),
|
||||
};
|
||||
|
@@ -68,6 +68,23 @@ export function useTableScroll(
|
||||
bodyEl = tableEl.querySelector('.ant-table-body');
|
||||
}
|
||||
|
||||
const hasScrollBarY = bodyEl.scrollHeight > bodyEl.clientHeight;
|
||||
const hasScrollBarX = bodyEl.scrollWidth > bodyEl.clientWidth;
|
||||
|
||||
if (hasScrollBarY) {
|
||||
tableEl.classList.contains('hide-scrollbar-y') &&
|
||||
tableEl.classList.remove('hide-scrollbar-y');
|
||||
} else {
|
||||
!tableEl.classList.contains('hide-scrollbar-y') && tableEl.classList.add('hide-scrollbar-y');
|
||||
}
|
||||
|
||||
if (hasScrollBarX) {
|
||||
tableEl.classList.contains('hide-scrollbar-x') &&
|
||||
tableEl.classList.remove('hide-scrollbar-x');
|
||||
} else {
|
||||
!tableEl.classList.contains('hide-scrollbar-x') && tableEl.classList.add('hide-scrollbar-x');
|
||||
}
|
||||
|
||||
bodyEl!.style.height = 'unset';
|
||||
|
||||
if (!unref(getCanResize) || tableData.length === 0) return;
|
||||
|
@@ -3,6 +3,7 @@ export type ComponentType =
|
||||
| 'InputNumber'
|
||||
| 'Select'
|
||||
| 'ApiSelect'
|
||||
| 'ApiTreeSelect'
|
||||
| 'Checkbox'
|
||||
| 'Switch'
|
||||
| 'DatePicker'
|
||||
|
@@ -1,8 +1,9 @@
|
||||
import { ButtonProps } from 'ant-design-vue/es/button/buttonTypes';
|
||||
import { TooltipProps } from 'ant-design-vue/es/tooltip/Tooltip';
|
||||
import { RoleEnum } from '/@/enums/roleEnum';
|
||||
export interface ActionItem extends ButtonProps {
|
||||
onClick?: Fn;
|
||||
label: string;
|
||||
label?: string;
|
||||
color?: 'success' | 'error' | 'warning';
|
||||
icon?: string;
|
||||
popConfirm?: PopConfirm;
|
||||
@@ -12,6 +13,7 @@ export interface ActionItem extends ButtonProps {
|
||||
auth?: RoleEnum | RoleEnum[] | string | string[];
|
||||
// 业务控制是否显示
|
||||
ifShow?: boolean | ((action: ActionItem) => boolean);
|
||||
tooltip?: string | TooltipProps;
|
||||
}
|
||||
|
||||
export interface PopConfirm {
|
||||
|
@@ -18,8 +18,8 @@
|
||||
import TreeHeader from './TreeHeader.vue';
|
||||
import { ScrollContainer } from '/@/components/Container';
|
||||
|
||||
import { omit, get } from 'lodash-es';
|
||||
import { isBoolean, isFunction } from '/@/utils/is';
|
||||
import { omit, get, difference } from 'lodash-es';
|
||||
import { isArray, isBoolean, isFunction } from '/@/utils/is';
|
||||
import { extendSlots, getSlot } from '/@/utils/helper/tsxHelper';
|
||||
import { filter } from '/@/utils/helper/treeHelper';
|
||||
|
||||
@@ -90,15 +90,25 @@
|
||||
emit('update:selectedKeys', v);
|
||||
},
|
||||
onCheck: (v: CheckKeys, e: CheckEvent) => {
|
||||
state.checkedKeys = v;
|
||||
const rawVal = toRaw(v);
|
||||
let currentValue = toRaw(state.checkedKeys) as Keys;
|
||||
if (isArray(currentValue) && searchState.startSearch) {
|
||||
const { key } = unref(getReplaceFields);
|
||||
currentValue = difference(currentValue, getChildrenKeys(e.node.$attrs.node[key]));
|
||||
if (e.checked) {
|
||||
currentValue.push(e.node.$attrs.node[key]);
|
||||
}
|
||||
state.checkedKeys = currentValue;
|
||||
} else {
|
||||
state.checkedKeys = v;
|
||||
}
|
||||
|
||||
const rawVal = toRaw(state.checkedKeys);
|
||||
emit('update:value', rawVal);
|
||||
emit('check', rawVal, e);
|
||||
},
|
||||
onRightClick: handleRightClick,
|
||||
};
|
||||
propsData = omit(propsData, 'treeData', 'class');
|
||||
return propsData;
|
||||
return omit(propsData, 'treeData', 'class');
|
||||
});
|
||||
|
||||
const getTreeData = computed((): TreeItem[] =>
|
||||
@@ -106,11 +116,18 @@
|
||||
);
|
||||
|
||||
const getNotFound = computed((): boolean => {
|
||||
return searchState.startSearch && searchState.searchData?.length === 0;
|
||||
return !getTreeData.value || getTreeData.value.length === 0;
|
||||
});
|
||||
|
||||
const { deleteNodeByKey, insertNodeByKey, filterByLevel, updateNodeByKey, getAllKeys } =
|
||||
useTree(treeDataRef, getReplaceFields);
|
||||
const {
|
||||
deleteNodeByKey,
|
||||
insertNodeByKey,
|
||||
insertNodesByKey,
|
||||
filterByLevel,
|
||||
updateNodeByKey,
|
||||
getAllKeys,
|
||||
getChildrenKeys,
|
||||
} = useTree(treeDataRef, getReplaceFields);
|
||||
|
||||
function getIcon(params: Recordable, icon?: string) {
|
||||
if (!icon) {
|
||||
@@ -267,6 +284,7 @@
|
||||
setCheckedKeys,
|
||||
getCheckedKeys,
|
||||
insertNodeByKey,
|
||||
insertNodesByKey,
|
||||
deleteNodeByKey,
|
||||
updateNodeByKey,
|
||||
checkAll,
|
||||
@@ -375,7 +393,7 @@
|
||||
</Tree>
|
||||
</ScrollContainer>
|
||||
|
||||
<Empty v-show={unref(getNotFound)} class="!mt-4" />
|
||||
<Empty v-show={unref(getNotFound)} image={Empty.PRESENTED_IMAGE_SIMPLE} class="!mt-4" />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@@ -31,6 +31,7 @@ export interface TreeActionType {
|
||||
getCheckedKeys: () => CheckKeys;
|
||||
filterByLevel: (level: number) => void;
|
||||
insertNodeByKey: (opt: InsertNodeParams) => void;
|
||||
insertNodesByKey: (opt: InsertNodeParams) => void;
|
||||
deleteNodeByKey: (key: string) => void;
|
||||
updateNodeByKey: (key: string, node: Omit<TreeDataItem, 'key'>) => void;
|
||||
}
|
||||
|
@@ -27,6 +27,28 @@ export function useTree(
|
||||
return keys as Keys;
|
||||
}
|
||||
|
||||
function getChildrenKeys(nodeKey: string | number, list?: TreeDataItem[]): Keys {
|
||||
const keys: Keys = [];
|
||||
const treeData = list || unref(treeDataRef);
|
||||
const { key: keyField, children: childrenField } = unref(getReplaceFields);
|
||||
if (!childrenField || !keyField) return keys;
|
||||
for (let index = 0; index < treeData.length; index++) {
|
||||
const node = treeData[index];
|
||||
const children = node[childrenField];
|
||||
if (nodeKey === node[keyField]) {
|
||||
keys.push(node[keyField]!);
|
||||
if (children && children.length) {
|
||||
keys.push(...(getAllKeys(children) as string[]));
|
||||
}
|
||||
} else {
|
||||
if (children && children.length) {
|
||||
keys.push(...getChildrenKeys(nodeKey, children));
|
||||
}
|
||||
}
|
||||
}
|
||||
return keys as Keys;
|
||||
}
|
||||
|
||||
// Update node
|
||||
function updateNodeByKey(key: string, node: TreeDataItem, list?: TreeDataItem[]) {
|
||||
if (!key) return;
|
||||
@@ -87,11 +109,39 @@ export function useTree(
|
||||
if (treeItem[keyField] === parentKey) {
|
||||
treeItem[childrenField] = treeItem[childrenField] || [];
|
||||
treeItem[childrenField][push](node);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
treeDataRef.value = treeData;
|
||||
}
|
||||
/**
|
||||
* 批量添加节点
|
||||
*/
|
||||
function insertNodesByKey({ parentKey = null, list, push = 'push' }: InsertNodeParams) {
|
||||
const treeData: any = cloneDeep(unref(treeDataRef));
|
||||
if (!list || list.length < 1) {
|
||||
return;
|
||||
}
|
||||
if (!parentKey) {
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
treeData[push](list[i]);
|
||||
}
|
||||
} else {
|
||||
const { key: keyField, children: childrenField } = unref(getReplaceFields);
|
||||
if (!childrenField || !keyField) return;
|
||||
|
||||
forEach(treeData, (treeItem) => {
|
||||
if (treeItem[keyField] === parentKey) {
|
||||
treeItem[childrenField] = treeItem[childrenField] || [];
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
treeItem[childrenField][push](list[i]);
|
||||
}
|
||||
treeDataRef.value = treeData;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
// Delete node
|
||||
function deleteNodeByKey(key: string, list?: TreeDataItem[]) {
|
||||
if (!key) return;
|
||||
@@ -111,5 +161,13 @@ export function useTree(
|
||||
}
|
||||
}
|
||||
}
|
||||
return { deleteNodeByKey, insertNodeByKey, filterByLevel, updateNodeByKey, getAllKeys };
|
||||
return {
|
||||
deleteNodeByKey,
|
||||
insertNodeByKey,
|
||||
insertNodesByKey,
|
||||
filterByLevel,
|
||||
updateNodeByKey,
|
||||
getAllKeys,
|
||||
getChildrenKeys,
|
||||
};
|
||||
}
|
||||
|
@@ -32,6 +32,7 @@
|
||||
:value="fileList"
|
||||
@register="registerPreviewModal"
|
||||
@list-change="handlePreviewChange"
|
||||
@delete="handlePreviewDelete"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
@@ -45,12 +46,13 @@
|
||||
import { uploadContainerProps } from './props';
|
||||
import { omit } from 'lodash-es';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { isArray } from '/@/utils/is';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'BasicUpload',
|
||||
components: { UploadModal, UploadPreviewModal, Icon, Tooltip },
|
||||
props: uploadContainerProps,
|
||||
emits: ['change', 'delete'],
|
||||
emits: ['change', 'delete', 'preview-delete', 'update:value'],
|
||||
|
||||
setup(props, { emit, attrs }) {
|
||||
const { t } = useI18n();
|
||||
@@ -76,7 +78,7 @@
|
||||
watch(
|
||||
() => props.value,
|
||||
(value = []) => {
|
||||
fileList.value = value;
|
||||
fileList.value = isArray(value) ? value : [];
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
@@ -84,12 +86,14 @@
|
||||
// 上传modal保存操作
|
||||
function handleChange(urls: string[]) {
|
||||
fileList.value = [...unref(fileList), ...(urls || [])];
|
||||
emit('update:value', fileList.value);
|
||||
emit('change', fileList.value);
|
||||
}
|
||||
|
||||
// 预览modal保存操作
|
||||
function handlePreviewChange(urls: string[]) {
|
||||
fileList.value = [...(urls || [])];
|
||||
emit('update:value', fileList.value);
|
||||
emit('change', fileList.value);
|
||||
}
|
||||
|
||||
@@ -97,6 +101,10 @@
|
||||
emit('delete', record);
|
||||
}
|
||||
|
||||
function handlePreviewDelete(url: string) {
|
||||
emit('preview-delete', url);
|
||||
}
|
||||
|
||||
return {
|
||||
registerUploadModal,
|
||||
openUploadModal,
|
||||
@@ -108,6 +116,7 @@
|
||||
showPreview,
|
||||
bindValue,
|
||||
handleDelete,
|
||||
handlePreviewDelete,
|
||||
t,
|
||||
};
|
||||
},
|
||||
|
@@ -20,11 +20,12 @@
|
||||
import { downloadByUrl } from '/@/utils/file/download';
|
||||
import { createPreviewColumns, createPreviewActionColumn } from './data';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { isArray } from '/@/utils/is';
|
||||
|
||||
export default defineComponent({
|
||||
components: { BasicModal, FileList },
|
||||
props: previewProps,
|
||||
emits: ['list-change', 'register'],
|
||||
emits: ['list-change', 'register', 'delete'],
|
||||
setup(props, { emit }) {
|
||||
const [register, { closeModal }] = useModalInner();
|
||||
const { t } = useI18n();
|
||||
@@ -33,6 +34,7 @@
|
||||
watch(
|
||||
() => props.value,
|
||||
(value) => {
|
||||
if (!isArray(value)) value = [];
|
||||
fileListRef.value = value
|
||||
.filter((item) => !!item)
|
||||
.map((item) => {
|
||||
@@ -50,7 +52,8 @@
|
||||
function handleRemove(record: PreviewFileItem) {
|
||||
const index = fileListRef.value.findIndex((item) => item.url === record.url);
|
||||
if (index !== -1) {
|
||||
fileListRef.value.splice(index, 1);
|
||||
const removed = fileListRef.value.splice(index, 1);
|
||||
emit('delete', removed[0].url);
|
||||
emit(
|
||||
'list-change',
|
||||
fileListRef.value.map((item) => item.url)
|
||||
|
@@ -1,18 +1,19 @@
|
||||
import type { App } from 'vue';
|
||||
import { Icon } from './Icon';
|
||||
// import { Icon } from './Icon';
|
||||
import { Button } from './Button';
|
||||
import {
|
||||
// Need
|
||||
Button as AntButton,
|
||||
Input,
|
||||
Layout,
|
||||
} from 'ant-design-vue';
|
||||
|
||||
const compList = [Icon, AntButton.Group];
|
||||
const compList = [AntButton.Group];
|
||||
|
||||
export function registerGlobComp(app: App) {
|
||||
compList.forEach((comp) => {
|
||||
app.component(comp.name || comp.displayName, comp);
|
||||
});
|
||||
|
||||
app.use(Input).use(Button);
|
||||
app.use(Input).use(Button).use(Layout);
|
||||
}
|
||||
|
@@ -59,7 +59,7 @@
|
||||
}
|
||||
|
||||
&.ant-btn-link.is-disabled {
|
||||
color: rgba(0, 0, 0, 0.25) !important;
|
||||
color: rgba(0, 0, 0, 0.25);
|
||||
text-shadow: none;
|
||||
cursor: not-allowed !important;
|
||||
background-color: transparent !important;
|
||||
|
@@ -1,6 +1,7 @@
|
||||
@import './pagination.less';
|
||||
@import './input.less';
|
||||
@import './btn.less';
|
||||
// @import './table.less';
|
||||
|
||||
// TODO beta.11 fix
|
||||
.ant-col {
|
||||
|
76
src/design/ant/table.less
Normal file
76
src/design/ant/table.less
Normal file
@@ -0,0 +1,76 @@
|
||||
@prefix-cls: ~'@{namespace}-basic-table';
|
||||
|
||||
// fix table unnecessary scrollbar
|
||||
.@{prefix-cls} {
|
||||
.hide-scrollbar-y {
|
||||
.ant-spin-nested-loading {
|
||||
.ant-spin-container {
|
||||
.ant-table {
|
||||
.ant-table-content {
|
||||
.ant-table-scroll {
|
||||
.ant-table-hide-scrollbar {
|
||||
overflow-y: auto !important;
|
||||
}
|
||||
|
||||
.ant-table-body {
|
||||
overflow-y: auto !important;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-table-fixed-right {
|
||||
.ant-table-body-outer {
|
||||
.ant-table-body-inner {
|
||||
overflow-y: auto !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ant-table-fixed-left {
|
||||
.ant-table-body-outer {
|
||||
.ant-table-body-inner {
|
||||
overflow-y: auto !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.hide-scrollbar-x {
|
||||
.ant-spin-nested-loading {
|
||||
.ant-spin-container {
|
||||
.ant-table {
|
||||
.ant-table-content {
|
||||
.ant-table-scroll {
|
||||
.ant-table-hide-scrollbar {
|
||||
//overflow-x: auto !important;
|
||||
}
|
||||
|
||||
.ant-table-body {
|
||||
overflow: auto !important;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-table-fixed-right {
|
||||
.ant-table-body-outer {
|
||||
.ant-table-body-inner {
|
||||
overflow-x: auto !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ant-table-fixed-left {
|
||||
.ant-table-body-outer {
|
||||
.ant-table-body-inner {
|
||||
overflow-x: auto !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@@ -33,6 +33,8 @@ export enum PermissionModeEnum {
|
||||
ROLE = 'ROLE',
|
||||
// black
|
||||
BACK = 'BACK',
|
||||
// route mapping
|
||||
ROUTE_MAPPING = 'ROUTE_MAPPING',
|
||||
}
|
||||
|
||||
// Route switching animation
|
||||
|
@@ -1,12 +1,22 @@
|
||||
import type { UnwrapRef } from 'vue';
|
||||
import { reactive, readonly, computed, getCurrentInstance, watchEffect } from 'vue';
|
||||
import type { UnwrapRef, Ref } from 'vue';
|
||||
import {
|
||||
reactive,
|
||||
readonly,
|
||||
computed,
|
||||
getCurrentInstance,
|
||||
watchEffect,
|
||||
unref,
|
||||
nextTick,
|
||||
toRaw,
|
||||
} from 'vue';
|
||||
|
||||
import { isEqual } from 'lodash-es';
|
||||
|
||||
export function useRuleFormItem<T extends Recordable>(
|
||||
props: T,
|
||||
key: keyof T = 'value',
|
||||
changeEvent = 'change'
|
||||
changeEvent = 'change',
|
||||
emitData?: Ref<any[]>
|
||||
) {
|
||||
const instance = getCurrentInstance();
|
||||
const emit = instance?.emit;
|
||||
@@ -33,7 +43,9 @@ export function useRuleFormItem<T extends Recordable>(
|
||||
if (isEqual(value, defaultState.value)) return;
|
||||
|
||||
innerState.value = value as T[keyof T];
|
||||
emit?.(changeEvent, value);
|
||||
nextTick(() => {
|
||||
emit?.(changeEvent, value, ...(toRaw(unref(emitData)) || []));
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
|
147
src/hooks/web/useContentHeight.ts
Normal file
147
src/hooks/web/useContentHeight.ts
Normal file
@@ -0,0 +1,147 @@
|
||||
import { ComputedRef, nextTick, Ref, ref, unref, watch } from 'vue';
|
||||
import { onMountedOrActivated } from '/@/hooks/core/onMountedOrActivated';
|
||||
import { useWindowSizeFn } from '/@/hooks/event/useWindowSizeFn';
|
||||
import { useLayoutHeight } from '/@/layouts/default/content/useContentViewHeight';
|
||||
import { getViewportOffset } from '/@/utils/domUtils';
|
||||
|
||||
export interface CompensationHeight {
|
||||
// 使用 layout Footer 高度作为判断补偿高度的条件
|
||||
useLayoutFooter: boolean;
|
||||
// refs HTMLElement
|
||||
elements?: Ref[];
|
||||
}
|
||||
|
||||
/**
|
||||
* 动态计算内容高度,根据锚点dom最下坐标到屏幕最下坐标,根据传入dom的高度、padding、margin等值进行动态计算
|
||||
* 最终获取合适的内容高度
|
||||
*
|
||||
* @param flag 用于开启计算的响应式标识
|
||||
* @param anchorRef 锚点组件 Ref<ElRef | ComponentRef>
|
||||
* @param subtractHeightRefs 待减去高度的组件列表 Ref<ElRef | ComponentRef>
|
||||
* @param substractSpaceRefs 待减去空闲空间(margins/paddings)的组件列表 Ref<ElRef | ComponentRef>
|
||||
* @param offsetHeightRef 计算偏移的响应式高度,计算高度时将直接减去此值
|
||||
* @returns 响应式高度
|
||||
*/
|
||||
export function useContentHeight(
|
||||
flag: ComputedRef<Boolean>,
|
||||
anchorRef: Ref,
|
||||
subtractHeightRefs: Ref[],
|
||||
substractSpaceRefs: Ref[],
|
||||
offsetHeightRef: Ref<number> = ref(0)
|
||||
) {
|
||||
const contentHeight: Ref<Nullable<number>> = ref(null);
|
||||
const { footerHeightRef: layoutFooterHeightRef } = useLayoutHeight();
|
||||
let compensationHeight: CompensationHeight = {
|
||||
useLayoutFooter: true,
|
||||
};
|
||||
|
||||
const setCompensation = (params: CompensationHeight) => {
|
||||
compensationHeight = params;
|
||||
};
|
||||
|
||||
function redoHeight() {
|
||||
nextTick(() => {
|
||||
calcContentHeight();
|
||||
});
|
||||
}
|
||||
|
||||
function calcSubtractSpace(element: HTMLDivElement | null | undefined): number {
|
||||
let subtractHeight = 0;
|
||||
const ZERO_PX = '0px';
|
||||
let marginBottom = ZERO_PX;
|
||||
let marginTop = ZERO_PX;
|
||||
if (element) {
|
||||
const cssStyle = getComputedStyle(element);
|
||||
marginBottom = cssStyle?.marginBottom ?? ZERO_PX;
|
||||
marginTop = cssStyle?.marginTop ?? ZERO_PX;
|
||||
}
|
||||
if (marginBottom) {
|
||||
const contentMarginBottom = Number(marginBottom.replace(/[^\d]/g, ''));
|
||||
subtractHeight += contentMarginBottom;
|
||||
}
|
||||
if (marginTop) {
|
||||
const contentMarginTop = Number(marginTop.replace(/[^\d]/g, ''));
|
||||
subtractHeight += contentMarginTop;
|
||||
}
|
||||
return subtractHeight;
|
||||
}
|
||||
|
||||
function getEl(element: any): Nullable<HTMLDivElement> {
|
||||
if (element == null) {
|
||||
return null;
|
||||
}
|
||||
return (element instanceof HTMLDivElement ? element : element.$el) as HTMLDivElement;
|
||||
}
|
||||
|
||||
async function calcContentHeight() {
|
||||
if (!flag.value) {
|
||||
return;
|
||||
}
|
||||
// Add a delay to get the correct height
|
||||
await nextTick();
|
||||
|
||||
const wrapperEl = getEl(unref(anchorRef));
|
||||
if (!wrapperEl) {
|
||||
return;
|
||||
}
|
||||
const { bottomIncludeBody } = getViewportOffset(wrapperEl);
|
||||
|
||||
// substract elements height
|
||||
let substractHeight = 0;
|
||||
subtractHeightRefs.forEach((item) => {
|
||||
substractHeight += getEl(unref(item))?.offsetHeight ?? 0;
|
||||
});
|
||||
|
||||
// subtract margins / paddings
|
||||
let substractSpaceHeight = 0;
|
||||
substractSpaceRefs.forEach((item) => {
|
||||
substractSpaceHeight += calcSubtractSpace(getEl(unref(item)));
|
||||
});
|
||||
|
||||
let height =
|
||||
bottomIncludeBody -
|
||||
unref(layoutFooterHeightRef) -
|
||||
unref(offsetHeightRef) -
|
||||
substractHeight -
|
||||
substractSpaceHeight;
|
||||
|
||||
// compensation height
|
||||
const calcCompensationHeight = () => {
|
||||
compensationHeight.elements?.forEach((item) => {
|
||||
height += getEl(unref(item))?.offsetHeight ?? 0;
|
||||
});
|
||||
};
|
||||
if (compensationHeight.useLayoutFooter && unref(layoutFooterHeightRef) > 0) {
|
||||
calcCompensationHeight();
|
||||
} else {
|
||||
calcCompensationHeight();
|
||||
}
|
||||
|
||||
contentHeight.value = height;
|
||||
}
|
||||
|
||||
onMountedOrActivated(() => {
|
||||
nextTick(() => {
|
||||
calcContentHeight();
|
||||
});
|
||||
});
|
||||
useWindowSizeFn(
|
||||
() => {
|
||||
calcContentHeight();
|
||||
},
|
||||
50,
|
||||
{ immediate: true }
|
||||
);
|
||||
watch(
|
||||
() => [layoutFooterHeightRef.value],
|
||||
() => {
|
||||
calcContentHeight();
|
||||
},
|
||||
{
|
||||
flush: 'post',
|
||||
immediate: true,
|
||||
}
|
||||
);
|
||||
|
||||
return { redoHeight, setCompensation, contentHeight };
|
||||
}
|
@@ -31,7 +31,7 @@ export function usePermission() {
|
||||
appStore.setProjectConfig({
|
||||
permissionMode:
|
||||
projectSetting.permissionMode === PermissionModeEnum.BACK
|
||||
? PermissionModeEnum.ROLE
|
||||
? PermissionModeEnum.ROUTE_MAPPING
|
||||
: PermissionModeEnum.BACK,
|
||||
});
|
||||
location.reload();
|
||||
@@ -57,13 +57,14 @@ export function usePermission() {
|
||||
* Determine whether there is permission
|
||||
*/
|
||||
function hasPermission(value?: RoleEnum | RoleEnum[] | string | string[], def = true): boolean {
|
||||
// Visible by default
|
||||
if (!value) {
|
||||
return def;
|
||||
}
|
||||
|
||||
const permMode = projectSetting.permissionMode;
|
||||
|
||||
if (PermissionModeEnum.ROLE === permMode) {
|
||||
// Visible by default
|
||||
if (!value) {
|
||||
return def;
|
||||
}
|
||||
if ([PermissionModeEnum.ROUTE_MAPPING, PermissionModeEnum.ROLE].includes(permMode)) {
|
||||
if (!isArray(value)) {
|
||||
return userStore.getRoleList?.includes(value as RoleEnum);
|
||||
}
|
||||
@@ -71,13 +72,9 @@ export function usePermission() {
|
||||
}
|
||||
|
||||
if (PermissionModeEnum.BACK === permMode) {
|
||||
// Visible by default
|
||||
if (!value) {
|
||||
return def;
|
||||
}
|
||||
const allCodeList = permissionStore.getPermCodeList;
|
||||
const allCodeList = permissionStore.getPermCodeList as string[];
|
||||
if (!isArray(value)) {
|
||||
return allCodeList.includes(value as string);
|
||||
return allCodeList.includes(value);
|
||||
}
|
||||
return (intersection(value, allCodeList) as string[]).length > 0;
|
||||
}
|
||||
@@ -89,9 +86,9 @@ export function usePermission() {
|
||||
* @param roles
|
||||
*/
|
||||
async function changeRole(roles: RoleEnum | RoleEnum[]): Promise<void> {
|
||||
if (projectSetting.permissionMode !== PermissionModeEnum.ROLE) {
|
||||
if (projectSetting.permissionMode !== PermissionModeEnum.ROUTE_MAPPING) {
|
||||
throw new Error(
|
||||
'Please switch PermissionModeEnum to ROLE mode in the configuration to operate!'
|
||||
'Please switch PermissionModeEnum to ROUTE_MAPPING mode in the configuration to operate!'
|
||||
);
|
||||
}
|
||||
|
||||
|
@@ -1,24 +1,36 @@
|
||||
import { getCurrentInstance, onBeforeUnmount, ref, Ref, unref } from 'vue';
|
||||
import { getCurrentInstance, onBeforeUnmount, ref, Ref, shallowRef, unref } from 'vue';
|
||||
import { useRafThrottle } from '/@/utils/domUtils';
|
||||
import { addResizeListener, removeResizeListener } from '/@/utils/event';
|
||||
import { isDef } from '/@/utils/is';
|
||||
|
||||
const domSymbol = Symbol('watermark-dom');
|
||||
|
||||
export function useWatermark(appendEl: Ref<HTMLElement | null> = ref(document.body)) {
|
||||
let func: Fn = () => {};
|
||||
export function useWatermark(
|
||||
appendEl: Ref<HTMLElement | null> = ref(document.body) as Ref<HTMLElement>
|
||||
) {
|
||||
const func = useRafThrottle(function () {
|
||||
const el = unref(appendEl);
|
||||
if (!el) return;
|
||||
const { clientHeight: height, clientWidth: width } = el;
|
||||
updateWatermark({ height, width });
|
||||
});
|
||||
const id = domSymbol.toString();
|
||||
const clear = () => {
|
||||
const domId = document.getElementById(id);
|
||||
if (domId) {
|
||||
const el = unref(appendEl);
|
||||
el && el.removeChild(domId);
|
||||
}
|
||||
window.removeEventListener('resize', func);
|
||||
};
|
||||
const createWatermark = (str: string) => {
|
||||
clear();
|
||||
const watermarkEl = shallowRef<HTMLElement>();
|
||||
|
||||
const clear = () => {
|
||||
const domId = unref(watermarkEl);
|
||||
watermarkEl.value = undefined;
|
||||
const el = unref(appendEl);
|
||||
if (!el) return;
|
||||
domId && el.removeChild(domId);
|
||||
removeResizeListener(el, func);
|
||||
};
|
||||
|
||||
function createBase64(str: string) {
|
||||
const can = document.createElement('canvas');
|
||||
can.width = 300;
|
||||
can.height = 240;
|
||||
const width = 300;
|
||||
const height = 240;
|
||||
Object.assign(can, { width, height });
|
||||
|
||||
const cans = can.getContext('2d');
|
||||
if (cans) {
|
||||
@@ -27,30 +39,55 @@ export function useWatermark(appendEl: Ref<HTMLElement | null> = ref(document.bo
|
||||
cans.fillStyle = 'rgba(0, 0, 0, 0.15)';
|
||||
cans.textAlign = 'left';
|
||||
cans.textBaseline = 'middle';
|
||||
cans.fillText(str, can.width / 20, can.height);
|
||||
cans.fillText(str, width / 20, height);
|
||||
}
|
||||
return can.toDataURL('image/png');
|
||||
}
|
||||
|
||||
function updateWatermark(
|
||||
options: {
|
||||
width?: number;
|
||||
height?: number;
|
||||
str?: string;
|
||||
} = {}
|
||||
) {
|
||||
const el = unref(watermarkEl);
|
||||
if (!el) return;
|
||||
if (isDef(options.width)) {
|
||||
el.style.width = `${options.width}px`;
|
||||
}
|
||||
if (isDef(options.height)) {
|
||||
el.style.height = `${options.height}px`;
|
||||
}
|
||||
if (isDef(options.str)) {
|
||||
el.style.background = `url(${createBase64(options.str)}) left top repeat`;
|
||||
}
|
||||
}
|
||||
|
||||
const createWatermark = (str: string) => {
|
||||
if (unref(watermarkEl)) {
|
||||
updateWatermark({ str });
|
||||
return id;
|
||||
}
|
||||
const div = document.createElement('div');
|
||||
watermarkEl.value = div;
|
||||
div.id = id;
|
||||
div.style.pointerEvents = 'none';
|
||||
div.style.top = '0px';
|
||||
div.style.left = '0px';
|
||||
div.style.position = 'absolute';
|
||||
div.style.zIndex = '100000';
|
||||
div.style.width = document.documentElement.clientWidth + 'px';
|
||||
div.style.height = document.documentElement.clientHeight + 'px';
|
||||
div.style.background = 'url(' + can.toDataURL('image/png') + ') left top repeat';
|
||||
const el = unref(appendEl);
|
||||
el && el.appendChild(div);
|
||||
if (!el) return id;
|
||||
const { clientHeight: height, clientWidth: width } = el;
|
||||
updateWatermark({ str, width, height });
|
||||
el.appendChild(div);
|
||||
return id;
|
||||
};
|
||||
|
||||
function setWatermark(str: string) {
|
||||
createWatermark(str);
|
||||
func = () => {
|
||||
createWatermark(str);
|
||||
};
|
||||
window.addEventListener('resize', func);
|
||||
addResizeListener(document.documentElement, func);
|
||||
const instance = getCurrentInstance();
|
||||
if (instance) {
|
||||
onBeforeUnmount(() => {
|
||||
|
@@ -19,7 +19,7 @@ export function useContentViewHeight() {
|
||||
const contentHeight = ref(window.innerHeight);
|
||||
const pageHeight = ref(window.innerHeight);
|
||||
const getViewHeight = computed(() => {
|
||||
return unref(contentHeight) - unref(headerHeightRef) || 0;
|
||||
return unref(contentHeight) - unref(headerHeightRef) - unref(footerHeightRef) || 0;
|
||||
});
|
||||
|
||||
useWindowSizeFn(
|
||||
|
@@ -5,7 +5,7 @@
|
||||
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
|
||||
import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useUserStoreWidthOut } from '/@/store/modules/user';
|
||||
import { useUserStoreWithOut } from '/@/store/modules/user';
|
||||
|
||||
import { SettingButtonPositionEnum } from '/@/enums/appEnum';
|
||||
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
|
||||
@@ -22,7 +22,7 @@
|
||||
setup() {
|
||||
const { getUseOpenBackTop, getShowSettingButton, getSettingButtonPosition, getFullContent } =
|
||||
useRootSetting();
|
||||
const userStore = useUserStoreWidthOut();
|
||||
const userStore = useUserStoreWithOut();
|
||||
const { prefixCls } = useDesign('setting-drawer-fearure');
|
||||
const { getShowHeader } = useHeaderSetting();
|
||||
|
||||
|
@@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<div :class="[prefixCls, `${prefixCls}--${theme}`]">
|
||||
<a-breadcrumb :routes="routes">
|
||||
<template #itemRender="{ route, routes, paths }">
|
||||
<template #itemRender="{ route, routes: routesMatched, paths }">
|
||||
<Icon :icon="getIcon(route)" v-if="getShowBreadCrumbIcon && getIcon(route)" />
|
||||
<span v-if="!hasRedirect(routes, route)">
|
||||
<span v-if="!hasRedirect(routesMatched, route)">
|
||||
{{ t(route.name || route.meta.title) }}
|
||||
</span>
|
||||
<router-link v-else to="" @click="handleClick(route, paths, $event)">
|
||||
@@ -15,6 +15,7 @@
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import type { RouteLocationMatched } from 'vue-router';
|
||||
import { useRouter } from 'vue-router';
|
||||
import type { Menu } from '/@/router/types';
|
||||
|
||||
import { defineComponent, ref, watchEffect } from 'vue';
|
||||
@@ -26,7 +27,6 @@
|
||||
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
|
||||
import { useGo } from '/@/hooks/web/usePage';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
import { isString } from '/@/utils/is';
|
||||
@@ -96,7 +96,7 @@
|
||||
}
|
||||
|
||||
function filterItem(list: RouteLocationMatched[]) {
|
||||
let resultList = filter(list, (item) => {
|
||||
return filter(list, (item) => {
|
||||
const { meta, name } = item;
|
||||
if (!meta) {
|
||||
return !!name;
|
||||
@@ -107,8 +107,6 @@
|
||||
}
|
||||
return true;
|
||||
}).filter((item) => !item.meta?.hideBreadcrumb || !item.meta?.hideMenu);
|
||||
|
||||
return resultList;
|
||||
}
|
||||
|
||||
function handleClick(route: RouteLocationMatched, paths: string[], e: Event) {
|
||||
@@ -140,10 +138,7 @@
|
||||
}
|
||||
|
||||
function hasRedirect(routes: RouteLocationMatched[], route: RouteLocationMatched) {
|
||||
if (routes.indexOf(route) === routes.length - 1) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return routes.indexOf(route) !== routes.length - 1;
|
||||
}
|
||||
|
||||
function getIcon(route) {
|
||||
|
@@ -1,11 +1,20 @@
|
||||
<template>
|
||||
<a-list :class="prefixCls">
|
||||
<template v-for="item in list" :key="item.id">
|
||||
<a-list :class="prefixCls" bordered :pagination="getPagination">
|
||||
<template v-for="item in getData" :key="item.id">
|
||||
<a-list-item class="list-item">
|
||||
<a-list-item-meta>
|
||||
<template #title>
|
||||
<div class="title">
|
||||
{{ item.title }}
|
||||
<a-typography-paragraph
|
||||
@click="handleTitleClick(item)"
|
||||
style="width: 100%; margin-bottom: 0 !important"
|
||||
:style="{ cursor: isTitleClickable ? 'pointer' : '' }"
|
||||
:delete="!!item.titleDelete"
|
||||
:ellipsis="
|
||||
$props.titleRows > 0 ? { rows: $props.titleRows, tooltip: item.title } : false
|
||||
"
|
||||
:content="item.title"
|
||||
/>
|
||||
<div class="extra" v-if="item.extra">
|
||||
<a-tag class="tag" :color="item.color">
|
||||
{{ item.extra }}
|
||||
@@ -21,8 +30,16 @@
|
||||
|
||||
<template #description>
|
||||
<div>
|
||||
<div class="description">
|
||||
{{ item.description }}
|
||||
<div class="description" v-if="item.description">
|
||||
<a-typography-paragraph
|
||||
style="width: 100%; margin-bottom: 0 !important"
|
||||
:ellipsis="
|
||||
$props.descRows > 0
|
||||
? { rows: $props.descRows, tooltip: item.description }
|
||||
: false
|
||||
"
|
||||
:content="item.description"
|
||||
/>
|
||||
</div>
|
||||
<div class="datetime">
|
||||
{{ item.datetime }}
|
||||
@@ -35,16 +52,18 @@
|
||||
</a-list>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType } from 'vue';
|
||||
import { computed, defineComponent, PropType, ref, watch, unref } from 'vue';
|
||||
import { ListItem } from './data';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { List, Avatar, Tag } from 'ant-design-vue';
|
||||
import { List, Avatar, Tag, Typography } from 'ant-design-vue';
|
||||
import { isNumber } from '/@/utils/is';
|
||||
export default defineComponent({
|
||||
components: {
|
||||
[Avatar.name]: Avatar,
|
||||
[List.name]: List,
|
||||
[List.Item.name]: List.Item,
|
||||
AListItemMeta: List.Item.Meta,
|
||||
ATypographyParagraph: Typography.Paragraph,
|
||||
[Tag.name]: Tag,
|
||||
},
|
||||
props: {
|
||||
@@ -52,10 +71,67 @@
|
||||
type: Array as PropType<ListItem[]>,
|
||||
default: () => [],
|
||||
},
|
||||
pageSize: {
|
||||
type: [Boolean, Number] as PropType<Boolean | Number>,
|
||||
default: 5,
|
||||
},
|
||||
currentPage: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
},
|
||||
titleRows: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
},
|
||||
descRows: {
|
||||
type: Number,
|
||||
default: 2,
|
||||
},
|
||||
onTitleClick: {
|
||||
type: Function as PropType<(Recordable) => void>,
|
||||
},
|
||||
},
|
||||
setup() {
|
||||
emits: ['update:currentPage'],
|
||||
setup(props, { emit }) {
|
||||
const { prefixCls } = useDesign('header-notify-list');
|
||||
return { prefixCls };
|
||||
const current = ref(props.currentPage || 1);
|
||||
const getData = computed(() => {
|
||||
const { pageSize, list } = props;
|
||||
console.log('refreshData', list);
|
||||
if (pageSize === false) return [];
|
||||
let size = isNumber(pageSize) ? pageSize : 5;
|
||||
return list.slice(size * (unref(current) - 1), size * unref(current));
|
||||
});
|
||||
watch(
|
||||
() => props.currentPage,
|
||||
(v) => {
|
||||
current.value = v;
|
||||
}
|
||||
);
|
||||
const isTitleClickable = computed(() => !!props.onTitleClick);
|
||||
const getPagination = computed(() => {
|
||||
const { list, pageSize } = props;
|
||||
if (pageSize > 0 && list && list.length > pageSize) {
|
||||
return {
|
||||
total: list.length,
|
||||
pageSize,
|
||||
//size: 'small',
|
||||
current: unref(current),
|
||||
onChange(page) {
|
||||
current.value = page;
|
||||
emit('update:currentPage', page);
|
||||
},
|
||||
};
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
function handleTitleClick(item: ListItem) {
|
||||
props.onTitleClick && props.onTitleClick(item);
|
||||
}
|
||||
|
||||
return { prefixCls, getPagination, getData, handleTitleClick, isTitleClickable };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
@@ -67,6 +143,10 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
::v-deep(.ant-pagination-disabled) {
|
||||
display: inline-block !important;
|
||||
}
|
||||
|
||||
&-item {
|
||||
padding: 6px;
|
||||
overflow: hidden;
|
||||
|
@@ -1,7 +1,10 @@
|
||||
export interface ListItem {
|
||||
id: string;
|
||||
avatar: string;
|
||||
// 通知的标题内容
|
||||
title: string;
|
||||
// 是否在标题上显示删除线
|
||||
titleDelete?: boolean;
|
||||
datetime: string;
|
||||
type: string;
|
||||
read?: boolean;
|
||||
@@ -56,6 +59,55 @@ export const tabListData: TabItem[] = [
|
||||
datetime: '2017-08-07',
|
||||
type: '1',
|
||||
},
|
||||
{
|
||||
id: '000000005',
|
||||
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/GvqBnKhFgObvnSGkDsje.png',
|
||||
title:
|
||||
'标题可以设置自动显示省略号,本例中标题行数已设为1行,如果内容超过1行将自动截断并支持tooltip显示完整标题。',
|
||||
description: '',
|
||||
datetime: '2017-08-07',
|
||||
type: '1',
|
||||
},
|
||||
{
|
||||
id: '000000006',
|
||||
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/GvqBnKhFgObvnSGkDsje.png',
|
||||
title: '左侧图标用于区分不同的类型',
|
||||
description: '',
|
||||
datetime: '2017-08-07',
|
||||
type: '1',
|
||||
},
|
||||
{
|
||||
id: '000000007',
|
||||
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/GvqBnKhFgObvnSGkDsje.png',
|
||||
title: '左侧图标用于区分不同的类型',
|
||||
description: '',
|
||||
datetime: '2017-08-07',
|
||||
type: '1',
|
||||
},
|
||||
{
|
||||
id: '000000008',
|
||||
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/GvqBnKhFgObvnSGkDsje.png',
|
||||
title: '左侧图标用于区分不同的类型',
|
||||
description: '',
|
||||
datetime: '2017-08-07',
|
||||
type: '1',
|
||||
},
|
||||
{
|
||||
id: '000000009',
|
||||
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/GvqBnKhFgObvnSGkDsje.png',
|
||||
title: '左侧图标用于区分不同的类型',
|
||||
description: '',
|
||||
datetime: '2017-08-07',
|
||||
type: '1',
|
||||
},
|
||||
{
|
||||
id: '000000010',
|
||||
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/GvqBnKhFgObvnSGkDsje.png',
|
||||
title: '左侧图标用于区分不同的类型',
|
||||
description: '',
|
||||
datetime: '2017-08-07',
|
||||
type: '1',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -84,7 +136,8 @@ export const tabListData: TabItem[] = [
|
||||
id: '000000008',
|
||||
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg',
|
||||
title: '标题',
|
||||
description: '这种模板用于提醒谁与你发生了互动',
|
||||
description:
|
||||
'请将鼠标移动到此处,以便测试超长的消息在此处将如何处理。本例中设置的描述最大行数为2,超过2行的描述内容将被省略并且可以通过tooltip查看完整内容',
|
||||
datetime: '2017-08-07',
|
||||
type: '2',
|
||||
clickClose: true,
|
||||
|
@@ -6,13 +6,15 @@
|
||||
</Badge>
|
||||
<template #content>
|
||||
<Tabs>
|
||||
<template v-for="item in tabListData" :key="item.key">
|
||||
<template v-for="item in listData" :key="item.key">
|
||||
<TabPane>
|
||||
<template #tab>
|
||||
{{ item.name }}
|
||||
<span v-if="item.list.length !== 0">({{ item.list.length }})</span>
|
||||
</template>
|
||||
<NoticeList :list="item.list" />
|
||||
<!-- 绑定title-click事件的通知列表中标题是“可点击”的-->
|
||||
<NoticeList :list="item.list" v-if="item.key === '1'" @title-click="onNoticeClick" />
|
||||
<NoticeList :list="item.list" v-else />
|
||||
</TabPane>
|
||||
</template>
|
||||
</Tabs>
|
||||
@@ -21,28 +23,40 @@
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { computed, defineComponent, ref } from 'vue';
|
||||
import { Popover, Tabs, Badge } from 'ant-design-vue';
|
||||
import { BellOutlined } from '@ant-design/icons-vue';
|
||||
import { tabListData } from './data';
|
||||
import { tabListData, ListItem } from './data';
|
||||
import NoticeList from './NoticeList.vue';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
|
||||
export default defineComponent({
|
||||
components: { Popover, BellOutlined, Tabs, TabPane: Tabs.TabPane, Badge, NoticeList },
|
||||
setup() {
|
||||
const { prefixCls } = useDesign('header-notify');
|
||||
const { createMessage } = useMessage();
|
||||
const listData = ref(tabListData);
|
||||
|
||||
let count = 0;
|
||||
const count = computed(() => {
|
||||
let count = 0;
|
||||
for (let i = 0; i < tabListData.length; i++) {
|
||||
count += tabListData[i].list.length;
|
||||
}
|
||||
return count;
|
||||
});
|
||||
|
||||
for (let i = 0; i < tabListData.length; i++) {
|
||||
count += tabListData[i].list.length;
|
||||
function onNoticeClick(record: ListItem) {
|
||||
createMessage.success('你点击了通知,ID=' + record.id);
|
||||
// 可以直接将其标记为已读(为标题添加删除线),此处演示的代码会切换删除线状态
|
||||
record.titleDelete = !record.titleDelete;
|
||||
}
|
||||
|
||||
return {
|
||||
prefixCls,
|
||||
tabListData,
|
||||
listData,
|
||||
count,
|
||||
onNoticeClick,
|
||||
numberStyle: {},
|
||||
};
|
||||
},
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<MenuItem :key="key">
|
||||
<MenuItem :key="itemKey">
|
||||
<span class="flex items-center">
|
||||
<Icon :icon="icon" class="mr-1" />
|
||||
<span>{{ text }}</span>
|
||||
@@ -9,7 +9,7 @@
|
||||
<script lang="ts">
|
||||
import { Menu } from 'ant-design-vue';
|
||||
|
||||
import { defineComponent } from 'vue';
|
||||
import { computed, defineComponent, getCurrentInstance } from 'vue';
|
||||
|
||||
import Icon from '/@/components/Icon/index';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
@@ -22,5 +22,10 @@
|
||||
text: propTypes.string,
|
||||
icon: propTypes.string,
|
||||
},
|
||||
setup(props) {
|
||||
const instance = getCurrentInstance();
|
||||
const itemKey = computed(() => props.key || instance?.vnode?.props?.key);
|
||||
return { itemKey };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
@@ -1,13 +1,10 @@
|
||||
import type { Menu } from '/@/router/types';
|
||||
import type { Ref } from 'vue';
|
||||
|
||||
import { watch, unref, ref, computed } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
import { MenuSplitTyeEnum } from '/@/enums/menuEnum';
|
||||
import { useThrottleFn } from '@vueuse/core';
|
||||
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
||||
|
||||
import { getChildrenMenus, getCurrentParentPath, getMenus, getShallowMenus } from '/@/router/menus';
|
||||
import { usePermissionStore } from '/@/store/modules/permission';
|
||||
import { useAppInject } from '/@/hooks/web/useAppInject';
|
||||
|
@@ -15,6 +15,7 @@
|
||||
:collapsedWidth="getCollapsedWidth"
|
||||
:theme="getMenuTheme"
|
||||
@breakpoint="onBreakpointChange"
|
||||
:trigger="getTrigger"
|
||||
v-bind="getTriggerAttr"
|
||||
>
|
||||
<template #trigger v-if="getShowTrigger">
|
||||
@@ -25,7 +26,7 @@
|
||||
</Sider>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, ref, unref, CSSProperties } from 'vue';
|
||||
import { computed, defineComponent, ref, unref, CSSProperties, h } from 'vue';
|
||||
|
||||
import { Layout } from 'ant-design-vue';
|
||||
import LayoutMenu from '../menu/index.vue';
|
||||
@@ -55,6 +56,7 @@
|
||||
getMenuHidden,
|
||||
getMenuFixed,
|
||||
getIsMixMode,
|
||||
toggleCollapsed,
|
||||
} = useMenuSetting();
|
||||
|
||||
const { prefixCls } = useDesign('layout-sideBar');
|
||||
@@ -101,6 +103,10 @@
|
||||
};
|
||||
});
|
||||
|
||||
// 在此处使用计算量可能会导致sider异常
|
||||
// andv 更新后,如果trigger插槽可用,则此处代码可废弃
|
||||
const getTrigger = h(LayoutTrigger);
|
||||
|
||||
return {
|
||||
prefixCls,
|
||||
sideRef,
|
||||
@@ -108,6 +114,7 @@
|
||||
getIsMobile,
|
||||
getHiddenDomStyle,
|
||||
getSiderClass,
|
||||
getTrigger,
|
||||
getTriggerAttr,
|
||||
getCollapsedWidth,
|
||||
getMenuFixed,
|
||||
@@ -119,6 +126,7 @@
|
||||
getMode,
|
||||
getSplitType,
|
||||
getShowTrigger,
|
||||
toggleCollapsed,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
@@ -15,7 +15,7 @@
|
||||
>
|
||||
<AppLogo :showTitle="false" :class="`${prefixCls}-logo`" />
|
||||
|
||||
<Trigger :class="`${prefixCls}-trigger`" />
|
||||
<LayoutTrigger :class="`${prefixCls}-trigger`" />
|
||||
|
||||
<ScrollContainer>
|
||||
<ul :class="`${prefixCls}-module`">
|
||||
@@ -63,7 +63,7 @@
|
||||
</div>
|
||||
<ScrollContainer :class="`${prefixCls}-menu-list__content`">
|
||||
<SimpleMenu
|
||||
:items="chilrenMenus"
|
||||
:items="childrenMenus"
|
||||
:theme="getMenuTheme"
|
||||
mixSider
|
||||
@menuClick="handleMenuClick"
|
||||
@@ -80,29 +80,23 @@
|
||||
<script lang="ts">
|
||||
import type { Menu } from '/@/router/types';
|
||||
import type { CSSProperties } from 'vue';
|
||||
import { computed, defineComponent, onMounted, ref, unref } from 'vue';
|
||||
import type { RouteLocationNormalized } from 'vue-router';
|
||||
|
||||
import { defineComponent, onMounted, ref, computed, unref } from 'vue';
|
||||
|
||||
import { ScrollContainer } from '/@/components/Container';
|
||||
import { SimpleMenuTag } from '/@/components/SimpleMenu';
|
||||
import { SimpleMenu, SimpleMenuTag } from '/@/components/SimpleMenu';
|
||||
import { Icon } from '/@/components/Icon';
|
||||
import { AppLogo } from '/@/components/Application';
|
||||
import Trigger from '../trigger/HeaderTrigger.vue';
|
||||
|
||||
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
||||
import { useDragLine } from './useLayoutSider';
|
||||
import { useGlobSetting } from '/@/hooks/setting';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { useGo } from '/@/hooks/web/usePage';
|
||||
|
||||
import { SIDE_BAR_SHOW_TIT_MINI_WIDTH, SIDE_BAR_MINI_WIDTH } from '/@/enums/appEnum';
|
||||
|
||||
import { SIDE_BAR_MINI_WIDTH, SIDE_BAR_SHOW_TIT_MINI_WIDTH } from '/@/enums/appEnum';
|
||||
import clickOutside from '/@/directives/clickOutside';
|
||||
import { getShallowMenus, getChildrenMenus, getCurrentParentPath } from '/@/router/menus';
|
||||
import { getChildrenMenus, getCurrentParentPath, getShallowMenus } from '/@/router/menus';
|
||||
import { listenerRouteChange } from '/@/logics/mitt/routeChange';
|
||||
import { SimpleMenu } from '/@/components/SimpleMenu';
|
||||
import LayoutTrigger from '../trigger/index.vue';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'LayoutMixSider',
|
||||
@@ -111,7 +105,7 @@
|
||||
AppLogo,
|
||||
SimpleMenu,
|
||||
Icon,
|
||||
Trigger,
|
||||
LayoutTrigger,
|
||||
SimpleMenuTag,
|
||||
},
|
||||
directives: {
|
||||
@@ -120,7 +114,7 @@
|
||||
setup() {
|
||||
let menuModules = ref<Menu[]>([]);
|
||||
const activePath = ref('');
|
||||
const chilrenMenus = ref<Menu[]>([]);
|
||||
const childrenMenus = ref<Menu[]>([]);
|
||||
const openMenu = ref(false);
|
||||
const dragBarRef = ref<ElRef>(null);
|
||||
const sideRef = ref<ElRef>(null);
|
||||
@@ -156,7 +150,7 @@
|
||||
|
||||
const getIsFixed = computed(() => {
|
||||
/* eslint-disable-next-line */
|
||||
mixSideHasChildren.value = unref(chilrenMenus).length > 0;
|
||||
mixSideHasChildren.value = unref(childrenMenus).length > 0;
|
||||
const isFixed = unref(getMixSideFixed) && unref(mixSideHasChildren);
|
||||
if (isFixed) {
|
||||
/* eslint-disable-next-line */
|
||||
@@ -184,6 +178,7 @@
|
||||
return !unref(getMixSideFixed)
|
||||
? {
|
||||
onMouseleave: () => {
|
||||
setActive(true);
|
||||
closeMenu();
|
||||
},
|
||||
}
|
||||
@@ -214,9 +209,8 @@
|
||||
}
|
||||
|
||||
// Process module menu click
|
||||
async function hanldeModuleClick(path: string, hover = false) {
|
||||
async function handleModuleClick(path: string, hover = false) {
|
||||
const children = await getChildrenMenus(path);
|
||||
|
||||
if (unref(activePath) === path) {
|
||||
if (!hover) {
|
||||
if (!unref(openMenu)) {
|
||||
@@ -224,6 +218,10 @@
|
||||
} else {
|
||||
closeMenu();
|
||||
}
|
||||
} else {
|
||||
if (!unref(openMenu)) {
|
||||
openMenu.value = true;
|
||||
}
|
||||
}
|
||||
if (!unref(openMenu)) {
|
||||
setActive();
|
||||
@@ -234,20 +232,19 @@
|
||||
}
|
||||
|
||||
if (!children || children.length === 0) {
|
||||
go(path);
|
||||
chilrenMenus.value = [];
|
||||
if (!hover) go(path);
|
||||
childrenMenus.value = [];
|
||||
closeMenu();
|
||||
return;
|
||||
}
|
||||
chilrenMenus.value = children;
|
||||
childrenMenus.value = children;
|
||||
}
|
||||
|
||||
// Set the currently active menu and submenu
|
||||
async function setActive(setChildren = false) {
|
||||
const path = currentRoute.value?.path;
|
||||
if (!path) return;
|
||||
const parentPath = await getCurrentParentPath(path);
|
||||
activePath.value = parentPath;
|
||||
activePath.value = await getCurrentParentPath(path);
|
||||
// hanldeModuleClick(parentPath);
|
||||
if (unref(getIsMixSidebar)) {
|
||||
const activeMenu = unref(menuModules).find((item) => item.path === unref(activePath));
|
||||
@@ -255,14 +252,14 @@
|
||||
if (p) {
|
||||
const children = await getChildrenMenus(p);
|
||||
if (setChildren) {
|
||||
chilrenMenus.value = children;
|
||||
childrenMenus.value = children;
|
||||
|
||||
if (unref(getMixSideFixed)) {
|
||||
openMenu.value = children.length > 0;
|
||||
}
|
||||
}
|
||||
if (children.length === 0) {
|
||||
chilrenMenus.value = [];
|
||||
childrenMenus.value = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -280,11 +277,15 @@
|
||||
function getItemEvents(item: Menu) {
|
||||
if (unref(getMixSideTrigger) === 'hover') {
|
||||
return {
|
||||
onMouseenter: () => hanldeModuleClick(item.path, true),
|
||||
onMouseenter: () => handleModuleClick(item.path, true),
|
||||
onClick: async () => {
|
||||
const children = await getChildrenMenus(item.path);
|
||||
if (item.path && (!children || children.length === 0)) go(item.path);
|
||||
},
|
||||
};
|
||||
}
|
||||
return {
|
||||
onClick: () => hanldeModuleClick(item.path),
|
||||
onClick: () => handleModuleClick(item.path),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -305,9 +306,9 @@
|
||||
t,
|
||||
prefixCls,
|
||||
menuModules,
|
||||
hanldeModuleClick,
|
||||
handleModuleClick: handleModuleClick,
|
||||
activePath,
|
||||
chilrenMenus,
|
||||
childrenMenus: childrenMenus,
|
||||
getShowDragBar,
|
||||
handleMenuClick,
|
||||
getMenuStyle,
|
||||
@@ -485,23 +486,24 @@
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
padding: 6px;
|
||||
padding-left: 12px;
|
||||
font-size: 18px;
|
||||
font-size: 14px;
|
||||
color: rgba(255, 255, 255, 0.65);
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
background-color: @sider-dark-bg-color;
|
||||
background-color: @trigger-dark-bg-color;
|
||||
height: 36px;
|
||||
line-height: 36px;
|
||||
}
|
||||
|
||||
&.light &-trigger {
|
||||
color: rgba(0, 0, 0, 0.65);
|
||||
background-color: #fff;
|
||||
border-top: 1px solid #eee;
|
||||
}
|
||||
|
||||
&-menu-list {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
width: 0;
|
||||
width: 200px;
|
||||
height: calc(100%);
|
||||
background-color: #fff;
|
||||
|
@@ -13,6 +13,13 @@ export default {
|
||||
uploadSuccess: 'Uploaded success!',
|
||||
modalTitle: 'Avatar upload',
|
||||
okText: 'Confirm and upload',
|
||||
btn_reset: 'Reset',
|
||||
btn_rotate_left: 'Counterclockwise rotation',
|
||||
btn_rotate_right: 'Clockwise rotation',
|
||||
btn_scale_x: 'Flip horizontal',
|
||||
btn_scale_y: 'Flip vertical',
|
||||
btn_zoom_in: 'Zoom in',
|
||||
btn_zoom_out: 'Zoom out',
|
||||
},
|
||||
drawer: {
|
||||
loadingText: 'Loading...',
|
||||
@@ -41,6 +48,9 @@ export default {
|
||||
modal: {
|
||||
cancelText: 'Close',
|
||||
okText: 'Confirm',
|
||||
close: 'Close',
|
||||
maximize: 'Maximize',
|
||||
restore: 'Restore',
|
||||
},
|
||||
table: {
|
||||
settingDens: 'Density',
|
||||
|
@@ -81,6 +81,9 @@ export default {
|
||||
tab: 'Tab with parameters',
|
||||
tab1: 'Tab with parameter 1',
|
||||
tab2: 'Tab with parameter 2',
|
||||
menu: 'Menu with parameters',
|
||||
menu1: 'Menu with parameters 1',
|
||||
menu2: 'Menu with parameters 2',
|
||||
|
||||
ws: 'Websocket test',
|
||||
|
||||
@@ -163,7 +166,7 @@ export default {
|
||||
moduleName: 'System management',
|
||||
|
||||
account: 'Account management',
|
||||
|
||||
account_detail: 'Account detail',
|
||||
password: 'Change password',
|
||||
|
||||
dept: 'Department management',
|
||||
|
@@ -13,6 +13,13 @@ export default {
|
||||
uploadSuccess: '上传成功',
|
||||
modalTitle: '头像上传',
|
||||
okText: '确认并上传',
|
||||
btn_reset: '重置',
|
||||
btn_rotate_left: '逆时针旋转',
|
||||
btn_rotate_right: '顺时针旋转',
|
||||
btn_scale_x: '水平翻转',
|
||||
btn_scale_y: '垂直翻转',
|
||||
btn_zoom_in: '放大',
|
||||
btn_zoom_out: '缩小',
|
||||
},
|
||||
drawer: {
|
||||
loadingText: '加载中...',
|
||||
@@ -43,6 +50,9 @@ export default {
|
||||
modal: {
|
||||
cancelText: '关闭',
|
||||
okText: '确认',
|
||||
close: '关闭',
|
||||
maximize: '最大化',
|
||||
restore: '还原',
|
||||
},
|
||||
table: {
|
||||
settingDens: '密度',
|
||||
|
@@ -80,6 +80,9 @@ export default {
|
||||
tab: 'Tab带参',
|
||||
tab1: 'Tab带参1',
|
||||
tab2: 'Tab带参2',
|
||||
menu: 'Menu带参',
|
||||
menu1: 'Menu带参1',
|
||||
menu2: 'Menu带参2',
|
||||
ws: 'websocket测试',
|
||||
breadcrumb: '面包屑导航',
|
||||
breadcrumbFlat: '平级模式',
|
||||
@@ -157,6 +160,7 @@ export default {
|
||||
system: {
|
||||
moduleName: '系统管理',
|
||||
account: '账号管理',
|
||||
account_detail: '账号详情',
|
||||
password: '修改密码',
|
||||
dept: '部门管理',
|
||||
menu: '菜单管理',
|
||||
|
@@ -1,9 +1,7 @@
|
||||
import '/@/design/index.less';
|
||||
import '/@/design/tailwind.css';
|
||||
|
||||
// Register icon sprite
|
||||
import 'virtual:svg-icons-register';
|
||||
|
||||
import App from './App.vue';
|
||||
import { createApp } from 'vue';
|
||||
import { initAppConfigStore } from '/@/logics/initAppConfig';
|
||||
@@ -42,7 +40,7 @@ async function bootstrap() {
|
||||
setupRouter(app);
|
||||
|
||||
// router-guard
|
||||
setupRouterGuard();
|
||||
setupRouterGuard(router);
|
||||
|
||||
// Register global directive
|
||||
setupGlobDirectives(app);
|
||||
|
@@ -2,6 +2,8 @@ export const REDIRECT_NAME = 'Redirect';
|
||||
|
||||
export const PARENT_LAYOUT_NAME = 'ParentLayout';
|
||||
|
||||
export const PAGE_NOT_FOUND_NAME = 'PageNotFound';
|
||||
|
||||
export const EXCEPTION_COMPONENT = () => import('../views/sys/exception/Exception.vue');
|
||||
|
||||
/**
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user