Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin
This commit is contained in:
commit
1fe260a391
34
.vscode/settings.json
vendored
34
.vscode/settings.json
vendored
@ -14,7 +14,6 @@
|
|||||||
"editor.tabSize": 2,
|
"editor.tabSize": 2,
|
||||||
"editor.detectIndentation": false,
|
"editor.detectIndentation": false,
|
||||||
"editor.cursorBlinking": "expand",
|
"editor.cursorBlinking": "expand",
|
||||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
|
||||||
"editor.largeFileOptimizations": false,
|
"editor.largeFileOptimizations": false,
|
||||||
"editor.accessibilitySupport": "off",
|
"editor.accessibilitySupport": "off",
|
||||||
"editor.cursorSmoothCaretAnimation": "on",
|
"editor.cursorSmoothCaretAnimation": "on",
|
||||||
@ -37,7 +36,34 @@
|
|||||||
"source.fixAll.stylelint": "explicit",
|
"source.fixAll.stylelint": "explicit",
|
||||||
"source.organizeImports": "never"
|
"source.organizeImports": "never"
|
||||||
},
|
},
|
||||||
|
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||||
|
"[html]": {
|
||||||
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
|
},
|
||||||
|
"[css]": {
|
||||||
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
|
},
|
||||||
|
"[scss]": {
|
||||||
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
|
},
|
||||||
|
"[javascript]": {
|
||||||
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
|
},
|
||||||
|
"[typescript]": {
|
||||||
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
|
},
|
||||||
|
"[json]": {
|
||||||
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
|
},
|
||||||
|
"[markdown]": {
|
||||||
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
|
},
|
||||||
|
"[jsonc]": {
|
||||||
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
|
},
|
||||||
|
"[vue]": {
|
||||||
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
|
},
|
||||||
// extensions
|
// extensions
|
||||||
"extensions.ignoreRecommendations": true,
|
"extensions.ignoreRecommendations": true,
|
||||||
|
|
||||||
@ -194,7 +220,7 @@
|
|||||||
"i18n-ally.keystyle": "nested",
|
"i18n-ally.keystyle": "nested",
|
||||||
"commentTranslate.multiLineMerge": true,
|
"commentTranslate.multiLineMerge": true,
|
||||||
"vue.server.hybridMode": true,
|
"vue.server.hybridMode": true,
|
||||||
"typescript.tsdk": "node_modules/typescript/lib",
|
|
||||||
"vitest.disableWorkspaceWarning": true,
|
"vitest.disableWorkspaceWarning": true,
|
||||||
"cSpell.words": ["tinymce"]
|
"cSpell.words": ["tinymce"],
|
||||||
|
"typescript.tsdk": "node_modules/typescript/lib"
|
||||||
}
|
}
|
||||||
|
@ -28,13 +28,13 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tinymce/tinymce-vue": "^6.0.1",
|
"@tinymce/tinymce-vue": "^6.0.1",
|
||||||
"@vben/access": "workspace:*",
|
"@vben/access": "workspace:*",
|
||||||
"@vben/chart-ui": "workspace:*",
|
|
||||||
"@vben/common-ui": "workspace:*",
|
"@vben/common-ui": "workspace:*",
|
||||||
"@vben/constants": "workspace:*",
|
"@vben/constants": "workspace:*",
|
||||||
"@vben/hooks": "workspace:*",
|
"@vben/hooks": "workspace:*",
|
||||||
"@vben/icons": "workspace:*",
|
"@vben/icons": "workspace:*",
|
||||||
"@vben/layouts": "workspace:*",
|
"@vben/layouts": "workspace:*",
|
||||||
"@vben/locales": "workspace:*",
|
"@vben/locales": "workspace:*",
|
||||||
|
"@vben/plugins": "workspace:*",
|
||||||
"@vben/preferences": "workspace:*",
|
"@vben/preferences": "workspace:*",
|
||||||
"@vben/request": "workspace:*",
|
"@vben/request": "workspace:*",
|
||||||
"@vben/stores": "workspace:*",
|
"@vben/stores": "workspace:*",
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
|
|
||||||
import { EchartsUI, type EchartsUIType, useEcharts } from '@vben/chart-ui';
|
import {
|
||||||
|
EchartsUI,
|
||||||
|
type EchartsUIType,
|
||||||
|
useEcharts,
|
||||||
|
} from '@vben/plugins/echarts';
|
||||||
|
|
||||||
const chartRef = ref<EchartsUIType>();
|
const chartRef = ref<EchartsUIType>();
|
||||||
const { renderEcharts } = useEcharts(chartRef);
|
const { renderEcharts } = useEcharts(chartRef);
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
|
|
||||||
import { EchartsUI, type EchartsUIType, useEcharts } from '@vben/chart-ui';
|
import {
|
||||||
|
EchartsUI,
|
||||||
|
type EchartsUIType,
|
||||||
|
useEcharts,
|
||||||
|
} from '@vben/plugins/echarts';
|
||||||
|
|
||||||
const chartRef = ref<EchartsUIType>();
|
const chartRef = ref<EchartsUIType>();
|
||||||
const { renderEcharts } = useEcharts(chartRef);
|
const { renderEcharts } = useEcharts(chartRef);
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
|
|
||||||
import { EchartsUI, type EchartsUIType, useEcharts } from '@vben/chart-ui';
|
import {
|
||||||
|
EchartsUI,
|
||||||
|
type EchartsUIType,
|
||||||
|
useEcharts,
|
||||||
|
} from '@vben/plugins/echarts';
|
||||||
|
|
||||||
const chartRef = ref<EchartsUIType>();
|
const chartRef = ref<EchartsUIType>();
|
||||||
const { renderEcharts } = useEcharts(chartRef);
|
const { renderEcharts } = useEcharts(chartRef);
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
|
|
||||||
import { EchartsUI, type EchartsUIType, useEcharts } from '@vben/chart-ui';
|
import {
|
||||||
|
EchartsUI,
|
||||||
|
type EchartsUIType,
|
||||||
|
useEcharts,
|
||||||
|
} from '@vben/plugins/echarts';
|
||||||
|
|
||||||
const chartRef = ref<EchartsUIType>();
|
const chartRef = ref<EchartsUIType>();
|
||||||
const { renderEcharts } = useEcharts(chartRef);
|
const { renderEcharts } = useEcharts(chartRef);
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
|
|
||||||
import { EchartsUI, type EchartsUIType, useEcharts } from '@vben/chart-ui';
|
import {
|
||||||
|
EchartsUI,
|
||||||
|
type EchartsUIType,
|
||||||
|
useEcharts,
|
||||||
|
} from '@vben/plugins/echarts';
|
||||||
|
|
||||||
const chartRef = ref<EchartsUIType>();
|
const chartRef = ref<EchartsUIType>();
|
||||||
const { renderEcharts } = useEcharts(chartRef);
|
const { renderEcharts } = useEcharts(chartRef);
|
||||||
|
@ -27,13 +27,13 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vben/access": "workspace:*",
|
"@vben/access": "workspace:*",
|
||||||
"@vben/chart-ui": "workspace:*",
|
|
||||||
"@vben/common-ui": "workspace:*",
|
"@vben/common-ui": "workspace:*",
|
||||||
"@vben/constants": "workspace:*",
|
"@vben/constants": "workspace:*",
|
||||||
"@vben/hooks": "workspace:*",
|
"@vben/hooks": "workspace:*",
|
||||||
"@vben/icons": "workspace:*",
|
"@vben/icons": "workspace:*",
|
||||||
"@vben/layouts": "workspace:*",
|
"@vben/layouts": "workspace:*",
|
||||||
"@vben/locales": "workspace:*",
|
"@vben/locales": "workspace:*",
|
||||||
|
"@vben/plugins": "workspace:*",
|
||||||
"@vben/preferences": "workspace:*",
|
"@vben/preferences": "workspace:*",
|
||||||
"@vben/request": "workspace:*",
|
"@vben/request": "workspace:*",
|
||||||
"@vben/stores": "workspace:*",
|
"@vben/stores": "workspace:*",
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
|
|
||||||
import { EchartsUI, type EchartsUIType, useEcharts } from '@vben/chart-ui';
|
import {
|
||||||
|
EchartsUI,
|
||||||
|
type EchartsUIType,
|
||||||
|
useEcharts,
|
||||||
|
} from '@vben/plugins/echarts';
|
||||||
|
|
||||||
const chartRef = ref<EchartsUIType>();
|
const chartRef = ref<EchartsUIType>();
|
||||||
const { renderEcharts } = useEcharts(chartRef);
|
const { renderEcharts } = useEcharts(chartRef);
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
|
|
||||||
import { EchartsUI, type EchartsUIType, useEcharts } from '@vben/chart-ui';
|
import {
|
||||||
|
EchartsUI,
|
||||||
|
type EchartsUIType,
|
||||||
|
useEcharts,
|
||||||
|
} from '@vben/plugins/echarts';
|
||||||
|
|
||||||
const chartRef = ref<EchartsUIType>();
|
const chartRef = ref<EchartsUIType>();
|
||||||
const { renderEcharts } = useEcharts(chartRef);
|
const { renderEcharts } = useEcharts(chartRef);
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
|
|
||||||
import { EchartsUI, type EchartsUIType, useEcharts } from '@vben/chart-ui';
|
import {
|
||||||
|
EchartsUI,
|
||||||
|
type EchartsUIType,
|
||||||
|
useEcharts,
|
||||||
|
} from '@vben/plugins/echarts';
|
||||||
|
|
||||||
const chartRef = ref<EchartsUIType>();
|
const chartRef = ref<EchartsUIType>();
|
||||||
const { renderEcharts } = useEcharts(chartRef);
|
const { renderEcharts } = useEcharts(chartRef);
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
|
|
||||||
import { EchartsUI, type EchartsUIType, useEcharts } from '@vben/chart-ui';
|
import {
|
||||||
|
EchartsUI,
|
||||||
|
type EchartsUIType,
|
||||||
|
useEcharts,
|
||||||
|
} from '@vben/plugins/echarts';
|
||||||
|
|
||||||
const chartRef = ref<EchartsUIType>();
|
const chartRef = ref<EchartsUIType>();
|
||||||
const { renderEcharts } = useEcharts(chartRef);
|
const { renderEcharts } = useEcharts(chartRef);
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
|
|
||||||
import { EchartsUI, type EchartsUIType, useEcharts } from '@vben/chart-ui';
|
import {
|
||||||
|
EchartsUI,
|
||||||
|
type EchartsUIType,
|
||||||
|
useEcharts,
|
||||||
|
} from '@vben/plugins/echarts';
|
||||||
|
|
||||||
const chartRef = ref<EchartsUIType>();
|
const chartRef = ref<EchartsUIType>();
|
||||||
const { renderEcharts } = useEcharts(chartRef);
|
const { renderEcharts } = useEcharts(chartRef);
|
||||||
|
@ -27,13 +27,13 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vben/access": "workspace:*",
|
"@vben/access": "workspace:*",
|
||||||
"@vben/chart-ui": "workspace:*",
|
|
||||||
"@vben/common-ui": "workspace:*",
|
"@vben/common-ui": "workspace:*",
|
||||||
"@vben/constants": "workspace:*",
|
"@vben/constants": "workspace:*",
|
||||||
"@vben/hooks": "workspace:*",
|
"@vben/hooks": "workspace:*",
|
||||||
"@vben/icons": "workspace:*",
|
"@vben/icons": "workspace:*",
|
||||||
"@vben/layouts": "workspace:*",
|
"@vben/layouts": "workspace:*",
|
||||||
"@vben/locales": "workspace:*",
|
"@vben/locales": "workspace:*",
|
||||||
|
"@vben/plugins": "workspace:*",
|
||||||
"@vben/preferences": "workspace:*",
|
"@vben/preferences": "workspace:*",
|
||||||
"@vben/request": "workspace:*",
|
"@vben/request": "workspace:*",
|
||||||
"@vben/stores": "workspace:*",
|
"@vben/stores": "workspace:*",
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
|
|
||||||
import { EchartsUI, type EchartsUIType, useEcharts } from '@vben/chart-ui';
|
import {
|
||||||
|
EchartsUI,
|
||||||
|
type EchartsUIType,
|
||||||
|
useEcharts,
|
||||||
|
} from '@vben/plugins/echarts';
|
||||||
|
|
||||||
const chartRef = ref<EchartsUIType>();
|
const chartRef = ref<EchartsUIType>();
|
||||||
const { renderEcharts } = useEcharts(chartRef);
|
const { renderEcharts } = useEcharts(chartRef);
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
|
|
||||||
import { EchartsUI, type EchartsUIType, useEcharts } from '@vben/chart-ui';
|
import {
|
||||||
|
EchartsUI,
|
||||||
|
type EchartsUIType,
|
||||||
|
useEcharts,
|
||||||
|
} from '@vben/plugins/echarts';
|
||||||
|
|
||||||
const chartRef = ref<EchartsUIType>();
|
const chartRef = ref<EchartsUIType>();
|
||||||
const { renderEcharts } = useEcharts(chartRef);
|
const { renderEcharts } = useEcharts(chartRef);
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
|
|
||||||
import { EchartsUI, type EchartsUIType, useEcharts } from '@vben/chart-ui';
|
import {
|
||||||
|
EchartsUI,
|
||||||
|
type EchartsUIType,
|
||||||
|
useEcharts,
|
||||||
|
} from '@vben/plugins/echarts';
|
||||||
|
|
||||||
const chartRef = ref<EchartsUIType>();
|
const chartRef = ref<EchartsUIType>();
|
||||||
const { renderEcharts } = useEcharts(chartRef);
|
const { renderEcharts } = useEcharts(chartRef);
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
|
|
||||||
import { EchartsUI, type EchartsUIType, useEcharts } from '@vben/chart-ui';
|
import {
|
||||||
|
EchartsUI,
|
||||||
|
type EchartsUIType,
|
||||||
|
useEcharts,
|
||||||
|
} from '@vben/plugins/echarts';
|
||||||
|
|
||||||
const chartRef = ref<EchartsUIType>();
|
const chartRef = ref<EchartsUIType>();
|
||||||
const { renderEcharts } = useEcharts(chartRef);
|
const { renderEcharts } = useEcharts(chartRef);
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
|
|
||||||
import { EchartsUI, type EchartsUIType, useEcharts } from '@vben/chart-ui';
|
import {
|
||||||
|
EchartsUI,
|
||||||
|
type EchartsUIType,
|
||||||
|
useEcharts,
|
||||||
|
} from '@vben/plugins/echarts';
|
||||||
|
|
||||||
const chartRef = ref<EchartsUIType>();
|
const chartRef = ref<EchartsUIType>();
|
||||||
const { renderEcharts } = useEcharts(chartRef);
|
const { renderEcharts } = useEcharts(chartRef);
|
||||||
|
@ -170,7 +170,7 @@ const defaultPreferences: Preferences = {
|
|||||||
locale: 'zh-CN',
|
locale: 'zh-CN',
|
||||||
loginExpiredMode: 'modal',
|
loginExpiredMode: 'modal',
|
||||||
name: 'Vben Admin',
|
name: 'Vben Admin',
|
||||||
preferencesButtonPosition: 'fixed',
|
preferencesButtonPosition: 'auto',
|
||||||
watermark: false,
|
watermark: false,
|
||||||
},
|
},
|
||||||
breadcrumb: {
|
breadcrumb: {
|
||||||
|
@ -11,7 +11,7 @@ The framework has built-in two types of access control methods:
|
|||||||
|
|
||||||
## Frontend Access Control
|
## Frontend Access Control
|
||||||
|
|
||||||
**Implementation Principle**: The permissions for routes are hardcoded on the frontend, specifying which permissions are required to view certain routes. Only general routes are initialized, and routes that require permissions are not added to the route table. After logging in or obtaining user roles through other means, the roles are used to traverse the route table to generate a route table that the role can access. This table is then added to the router instance using `router.addRoutes`, achieving permission filtering.
|
**Implementation Principle**: The permissions for routes are hardcoded on the frontend, specifying which permissions are required to view certain routes. Only general routes are initialized, and routes that require permissions are not added to the route table. After logging in or obtaining user roles through other means, the roles are used to traverse the route table to generate a route table that the role can access. This table is then added to the router instance using `router.addRoute`, achieving permission filtering.
|
||||||
|
|
||||||
**Disadvantage**: The permissions are relatively inflexible; if the backend changes roles, the frontend needs to be adjusted accordingly. This is suitable for systems with relatively fixed roles.
|
**Disadvantage**: The permissions are relatively inflexible; if the backend changes roles, the frontend needs to be adjusted accordingly. This is suitable for systems with relatively fixed roles.
|
||||||
|
|
||||||
@ -71,7 +71,7 @@ Sometimes, we need the menu to be visible but access to it forbidden. This can b
|
|||||||
|
|
||||||
## Backend Access Control
|
## Backend Access Control
|
||||||
|
|
||||||
**Implementation Principle**: It is achieved by dynamically generating a routing table through an API, which returns data following a certain structure. The frontend processes this data into a recognizable structure, then adds it to the routing instance using `router.addRoutes`, realizing the dynamic generation of permissions.
|
**Implementation Principle**: It is achieved by dynamically generating a routing table through an API, which returns data following a certain structure. The frontend processes this data into a recognizable structure, then adds it to the routing instance using `router.addRoute`, realizing the dynamic generation of permissions.
|
||||||
|
|
||||||
**Disadvantage**: The backend needs to provide a data structure that meets the standards, and the frontend needs to process this structure. This is suitable for systems with more complex permissions.
|
**Disadvantage**: The backend needs to provide a data structure that meets the standards, and the frontend needs to process this structure. This is suitable for systems with more complex permissions.
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ The directory uses Monorepo management, and the project structure is as follows:
|
|||||||
│ ├── constants # Constants
|
│ ├── constants # Constants
|
||||||
│ ├── effects # Effects related packages
|
│ ├── effects # Effects related packages
|
||||||
│ │ ├── access # Access control
|
│ │ ├── access # Access control
|
||||||
│ │ ├── chart-ui # Chart UI
|
│ │ ├── plugins # Plugins
|
||||||
│ │ ├── common-ui # Common UI
|
│ │ ├── common-ui # Common UI
|
||||||
│ │ ├── hooks # Composable APIs
|
│ │ ├── hooks # Composable APIs
|
||||||
│ │ ├── layouts # Layouts
|
│ │ ├── layouts # Layouts
|
||||||
|
@ -190,7 +190,7 @@ const defaultPreferences: Preferences = {
|
|||||||
locale: 'zh-CN',
|
locale: 'zh-CN',
|
||||||
loginExpiredMode: 'modal',
|
loginExpiredMode: 'modal',
|
||||||
name: 'Vben Admin',
|
name: 'Vben Admin',
|
||||||
preferencesButtonPosition: 'fixed',
|
preferencesButtonPosition: 'auto',
|
||||||
watermark: false,
|
watermark: false,
|
||||||
},
|
},
|
||||||
breadcrumb: {
|
breadcrumb: {
|
||||||
|
@ -11,7 +11,7 @@ outline: deep
|
|||||||
|
|
||||||
## 前端访问控制
|
## 前端访问控制
|
||||||
|
|
||||||
**实现原理**: 在前端固定写死路由的权限,指定路由有哪些权限可以查看。只初始化通用的路由,需要权限才能访问的路由没有被加入路由表内。在登陆后或者其他方式获取用户角色后,通过角色去遍历路由表,获取该角色可以访问的路由表,生成路由表,再通过 `router.addRoutes` 添加到路由实例,实现权限的过滤。
|
**实现原理**: 在前端固定写死路由的权限,指定路由有哪些权限可以查看。只初始化通用的路由,需要权限才能访问的路由没有被加入路由表内。在登陆后或者其他方式获取用户角色后,通过角色去遍历路由表,获取该角色可以访问的路由表,生成路由表,再通过 `router.addRoute` 添加到路由实例,实现权限的过滤。
|
||||||
|
|
||||||
**缺点**: 权限相对不自由,如果后台改动角色,前台也需要跟着改动。适合角色较固定的系统
|
**缺点**: 权限相对不自由,如果后台改动角色,前台也需要跟着改动。适合角色较固定的系统
|
||||||
|
|
||||||
@ -71,7 +71,7 @@ authStore.setUserInfo(userInfo);
|
|||||||
|
|
||||||
## 后端访问控制
|
## 后端访问控制
|
||||||
|
|
||||||
**实现原理**: 是通过接口动态生成路由表,且遵循一定的数据结构返回。前端根据需要处理该数据为可识别的结构,再通过 router.addRoutes 添加到路由实例,实现权限的动态生成。
|
**实现原理**: 是通过接口动态生成路由表,且遵循一定的数据结构返回。前端根据需要处理该数据为可识别的结构,再通过 `router.addRoute` 添加到路由实例,实现权限的动态生成。
|
||||||
|
|
||||||
**缺点**: 后端需要提供符合规范的数据结构,前端需要处理数据结构,适合权限较为复杂的系统。
|
**缺点**: 后端需要提供符合规范的数据结构,前端需要处理数据结构,适合权限较为复杂的系统。
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@
|
|||||||
│ ├── constants # 常量
|
│ ├── constants # 常量
|
||||||
│ ├── effects # 副作用相关包
|
│ ├── effects # 副作用相关包
|
||||||
│ │ ├── access # 访问控制
|
│ │ ├── access # 访问控制
|
||||||
│ │ ├── chart-ui # 图表 UI
|
│ │ ├── plugins # 第三方大型依赖插件
|
||||||
│ │ ├── common-ui # 通用 UI
|
│ │ ├── common-ui # 通用 UI
|
||||||
│ │ ├── hooks # 组合式 API
|
│ │ ├── hooks # 组合式 API
|
||||||
│ │ ├── layouts # 布局
|
│ │ ├── layouts # 布局
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
#app,
|
#app,
|
||||||
body,
|
body,
|
||||||
html {
|
html {
|
||||||
@apply size-full overscroll-none;
|
@apply !pointer-events-auto size-full overscroll-none;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||||
|
|
||||||
import { getElementVisibleRect } from '../dom'; // 假设函数位于 utils.ts 中
|
import { getElementVisibleRect } from '../dom';
|
||||||
|
|
||||||
describe('getElementVisibleRect', () => {
|
describe('getElementVisibleRect', () => {
|
||||||
// 设置浏览器视口尺寸的 mock
|
// 设置浏览器视口尺寸的 mock
|
||||||
|
@ -7,7 +7,6 @@ import {
|
|||||||
toLowerCaseFirstLetter,
|
toLowerCaseFirstLetter,
|
||||||
} from '../letter';
|
} from '../letter';
|
||||||
|
|
||||||
// 编写测试用例
|
|
||||||
describe('capitalizeFirstLetter', () => {
|
describe('capitalizeFirstLetter', () => {
|
||||||
it('should capitalize the first letter of a string', () => {
|
it('should capitalize the first letter of a string', () => {
|
||||||
expect(capitalizeFirstLetter('hello')).toBe('Hello');
|
expect(capitalizeFirstLetter('hello')).toBe('Hello');
|
||||||
|
@ -13,8 +13,7 @@ describe('uniqueByField', () => {
|
|||||||
|
|
||||||
const uniqueItems = uniqueByField(items, 'id');
|
const uniqueItems = uniqueByField(items, 'id');
|
||||||
|
|
||||||
// Assert expected results
|
expect(uniqueItems).toHaveLength(3);
|
||||||
expect(uniqueItems).toHaveLength(3); // After deduplication, there should be three objects left
|
|
||||||
expect(uniqueItems).toEqual([
|
expect(uniqueItems).toEqual([
|
||||||
{ id: 1, name: 'Item 1' },
|
{ id: 1, name: 'Item 1' },
|
||||||
{ id: 2, name: 'Item 2' },
|
{ id: 2, name: 'Item 2' },
|
||||||
|
3
packages/@core/base/typings/src/app.d.ts
vendored
3
packages/@core/base/typings/src/app.d.ts
vendored
@ -11,8 +11,9 @@ type ThemeModeType = 'auto' | 'dark' | 'light';
|
|||||||
* 偏好设置按钮位置
|
* 偏好设置按钮位置
|
||||||
* fixed 固定在右侧
|
* fixed 固定在右侧
|
||||||
* header 顶栏
|
* header 顶栏
|
||||||
|
* auto 自动
|
||||||
*/
|
*/
|
||||||
type PreferencesButtonPositionType = 'fixed' | 'header';
|
type PreferencesButtonPositionType = 'auto' | 'fixed' | 'header';
|
||||||
|
|
||||||
type BuiltinThemeType =
|
type BuiltinThemeType =
|
||||||
| 'custom'
|
| 'custom'
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
export * from './use-content-style';
|
export * from './use-content-style';
|
||||||
|
export * from './use-is-mobile';
|
||||||
export * from './use-namespace';
|
export * from './use-namespace';
|
||||||
export * from './use-priority-value';
|
export * from './use-priority-value';
|
||||||
export * from './use-sortable';
|
export * from './use-sortable';
|
||||||
|
@ -28,7 +28,7 @@ function useContentStyle() {
|
|||||||
position: 'fixed',
|
position: 'fixed',
|
||||||
top: `${top}px`,
|
top: `${top}px`,
|
||||||
width: `${width}px`,
|
width: `${width}px`,
|
||||||
zIndex: 1000,
|
zIndex: 150,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
7
packages/@core/composables/src/use-is-mobile.ts
Normal file
7
packages/@core/composables/src/use-is-mobile.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { breakpointsTailwind, useBreakpoints } from '@vueuse/core';
|
||||||
|
|
||||||
|
export function useIsMobile() {
|
||||||
|
const breakpoints = useBreakpoints(breakpointsTailwind);
|
||||||
|
const isMobile = breakpoints.smaller('md');
|
||||||
|
return { isMobile };
|
||||||
|
}
|
@ -20,7 +20,7 @@ const defaultPreferences: Preferences = {
|
|||||||
locale: 'zh-CN',
|
locale: 'zh-CN',
|
||||||
loginExpiredMode: 'page',
|
loginExpiredMode: 'page',
|
||||||
name: 'Vben Admin',
|
name: 'Vben Admin',
|
||||||
preferencesButtonPosition: 'fixed',
|
preferencesButtonPosition: 'auto',
|
||||||
watermark: false,
|
watermark: false,
|
||||||
},
|
},
|
||||||
breadcrumb: {
|
breadcrumb: {
|
||||||
|
@ -149,6 +149,45 @@ function usePreferences() {
|
|||||||
return enable && globalLockScreen;
|
return enable && globalLockScreen;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @zh_CN 偏好设置按钮位置
|
||||||
|
*/
|
||||||
|
const preferencesButtonPosition = computed(() => {
|
||||||
|
const { enablePreferences, preferencesButtonPosition } = preferences.app;
|
||||||
|
|
||||||
|
// 如果没有启用偏好设置按钮
|
||||||
|
if (!enablePreferences) {
|
||||||
|
return {
|
||||||
|
fixed: false,
|
||||||
|
header: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const { header, sidebar } = preferences;
|
||||||
|
const headerHidden = header.hidden;
|
||||||
|
const sidebarHidden = sidebar.hidden;
|
||||||
|
|
||||||
|
const contentIsMaximize = headerHidden && sidebarHidden;
|
||||||
|
|
||||||
|
const isHeaderPosition = preferencesButtonPosition === 'header';
|
||||||
|
|
||||||
|
// 如果设置了固定位置
|
||||||
|
if (preferencesButtonPosition !== 'auto') {
|
||||||
|
return {
|
||||||
|
fixed: preferencesButtonPosition === 'fixed',
|
||||||
|
header: isHeaderPosition,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果是全屏模式或者没有固定在顶部,
|
||||||
|
const fixed = contentIsMaximize || isFullContent.value || isMobile.value;
|
||||||
|
|
||||||
|
return {
|
||||||
|
fixed,
|
||||||
|
header: !fixed,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
authPanelCenter,
|
authPanelCenter,
|
||||||
authPanelLeft,
|
authPanelLeft,
|
||||||
@ -168,6 +207,7 @@ function usePreferences() {
|
|||||||
isSideNav,
|
isSideNav,
|
||||||
keepAlive,
|
keepAlive,
|
||||||
layout,
|
layout,
|
||||||
|
preferencesButtonPosition,
|
||||||
sidebarCollapsed,
|
sidebarCollapsed,
|
||||||
theme,
|
theme,
|
||||||
};
|
};
|
||||||
|
@ -4,6 +4,8 @@ import { computed, shallowRef, useSlots, watchEffect } from 'vue';
|
|||||||
|
|
||||||
import { VbenScrollbar } from '@vben-core/shadcn-ui';
|
import { VbenScrollbar } from '@vben-core/shadcn-ui';
|
||||||
|
|
||||||
|
import { useScrollLock } from '@vueuse/core';
|
||||||
|
|
||||||
import { SidebarCollapseButton, SidebarFixedButton } from './widgets';
|
import { SidebarCollapseButton, SidebarFixedButton } from './widgets';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@ -102,6 +104,7 @@ const expandOnHovering = defineModel<boolean>('expandOnHovering');
|
|||||||
const expandOnHover = defineModel<boolean>('expandOnHover');
|
const expandOnHover = defineModel<boolean>('expandOnHover');
|
||||||
const extraVisible = defineModel<boolean>('extraVisible');
|
const extraVisible = defineModel<boolean>('extraVisible');
|
||||||
|
|
||||||
|
const isLocked = useScrollLock(document.body);
|
||||||
const slots = useSlots();
|
const slots = useSlots();
|
||||||
|
|
||||||
const asideRef = shallowRef<HTMLDivElement | null>();
|
const asideRef = shallowRef<HTMLDivElement | null>();
|
||||||
@ -214,6 +217,7 @@ function handleMouseenter() {
|
|||||||
if (!expandOnHovering.value) {
|
if (!expandOnHovering.value) {
|
||||||
collapse.value = false;
|
collapse.value = false;
|
||||||
}
|
}
|
||||||
|
isLocked.value = true;
|
||||||
expandOnHovering.value = true;
|
expandOnHovering.value = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -224,6 +228,7 @@ function handleMouseleave() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isLocked.value = false;
|
||||||
expandOnHovering.value = false;
|
expandOnHovering.value = false;
|
||||||
collapse.value = true;
|
collapse.value = true;
|
||||||
extraVisible.value = false;
|
extraVisible.value = false;
|
||||||
|
@ -242,7 +242,7 @@ const tabbarStyle = computed((): CSSProperties => {
|
|||||||
let marginLeft = 0;
|
let marginLeft = 0;
|
||||||
|
|
||||||
// 如果不是混合导航,tabbar 的宽度为 100%
|
// 如果不是混合导航,tabbar 的宽度为 100%
|
||||||
if (!isMixedNav.value) {
|
if (!isMixedNav.value || props.sidebarHidden) {
|
||||||
width = '100%';
|
width = '100%';
|
||||||
} else if (sidebarEnable.value) {
|
} else if (sidebarEnable.value) {
|
||||||
// 鼠标在侧边栏上时,且侧边栏展开时的宽度
|
// 鼠标在侧边栏上时,且侧边栏展开时的宽度
|
||||||
|
@ -30,6 +30,8 @@ export class DrawerApi {
|
|||||||
const defaultState: DrawerState = {
|
const defaultState: DrawerState = {
|
||||||
cancelText: '取消',
|
cancelText: '取消',
|
||||||
closable: true,
|
closable: true,
|
||||||
|
closeOnClickModal: true,
|
||||||
|
closeOnPressEscape: true,
|
||||||
confirmLoading: false,
|
confirmLoading: false,
|
||||||
confirmText: '确定',
|
confirmText: '确定',
|
||||||
footer: true,
|
footer: true,
|
||||||
|
@ -7,12 +7,21 @@ export interface DrawerProps {
|
|||||||
* 取消按钮文字
|
* 取消按钮文字
|
||||||
*/
|
*/
|
||||||
cancelText?: string;
|
cancelText?: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否显示右上角的关闭按钮
|
* 是否显示右上角的关闭按钮
|
||||||
* @default true
|
* @default true
|
||||||
*/
|
*/
|
||||||
closable?: boolean;
|
closable?: boolean;
|
||||||
|
/**
|
||||||
|
* 点击弹窗遮罩是否关闭弹窗
|
||||||
|
* @default true
|
||||||
|
*/
|
||||||
|
closeOnClickModal?: boolean;
|
||||||
|
/**
|
||||||
|
* 按下 ESC 键是否关闭弹窗
|
||||||
|
* @default true
|
||||||
|
*/
|
||||||
|
closeOnPressEscape?: boolean;
|
||||||
/**
|
/**
|
||||||
* 确定按钮 loading
|
* 确定按钮 loading
|
||||||
* @default false
|
* @default false
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { DrawerProps, ExtendedDrawerApi } from './drawer';
|
import type { DrawerProps, ExtendedDrawerApi } from './drawer';
|
||||||
|
|
||||||
import { usePriorityValue } from '@vben-core/composables';
|
import { useIsMobile, usePriorityValue } from '@vben-core/composables';
|
||||||
import { Info, X } from '@vben-core/icons';
|
import { Info, X } from '@vben-core/icons';
|
||||||
import {
|
import {
|
||||||
Sheet,
|
Sheet,
|
||||||
@ -31,6 +31,7 @@ const props = withDefaults(defineProps<Props>(), {
|
|||||||
drawerApi: undefined,
|
drawerApi: undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { isMobile } = useIsMobile();
|
||||||
const state = props.drawerApi?.useStore?.();
|
const state = props.drawerApi?.useStore?.();
|
||||||
|
|
||||||
const title = usePriorityValue('title', props, state);
|
const title = usePriorityValue('title', props, state);
|
||||||
@ -43,6 +44,27 @@ const modal = usePriorityValue('modal', props, state);
|
|||||||
const confirmLoading = usePriorityValue('confirmLoading', props, state);
|
const confirmLoading = usePriorityValue('confirmLoading', props, state);
|
||||||
const cancelText = usePriorityValue('cancelText', props, state);
|
const cancelText = usePriorityValue('cancelText', props, state);
|
||||||
const confirmText = usePriorityValue('confirmText', props, state);
|
const confirmText = usePriorityValue('confirmText', props, state);
|
||||||
|
const closeOnClickModal = usePriorityValue('closeOnClickModal', props, state);
|
||||||
|
const closeOnPressEscape = usePriorityValue('closeOnPressEscape', props, state);
|
||||||
|
|
||||||
|
function interactOutside(e: Event) {
|
||||||
|
if (!closeOnClickModal.value) {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function escapeKeyDown(e: KeyboardEvent) {
|
||||||
|
if (!closeOnPressEscape.value) {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// pointer-down-outside
|
||||||
|
function pointerDownOutside(e: Event) {
|
||||||
|
const target = e.target as HTMLElement;
|
||||||
|
const isDismissableModal = !!target?.dataset.dismissableModal;
|
||||||
|
if (!closeOnClickModal.value || !isDismissableModal) {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<Sheet
|
<Sheet
|
||||||
@ -50,7 +72,16 @@ const confirmText = usePriorityValue('confirmText', props, state);
|
|||||||
:open="state?.isOpen"
|
:open="state?.isOpen"
|
||||||
@update:open="() => drawerApi?.close()"
|
@update:open="() => drawerApi?.close()"
|
||||||
>
|
>
|
||||||
<SheetContent :class="cn('flex w-[520px] flex-col', props.class, {})">
|
<SheetContent
|
||||||
|
:class="
|
||||||
|
cn('flex w-[520px] flex-col', props.class, {
|
||||||
|
'!w-full': isMobile,
|
||||||
|
})
|
||||||
|
"
|
||||||
|
@escape-key-down="escapeKeyDown"
|
||||||
|
@interact-outside="interactOutside"
|
||||||
|
@pointer-down-outside="pointerDownOutside"
|
||||||
|
>
|
||||||
<SheetHeader
|
<SheetHeader
|
||||||
:class="
|
:class="
|
||||||
cn('!flex flex-row items-center justify-between border-b px-6 py-5', {
|
cn('!flex flex-row items-center justify-between border-b px-6 py-5', {
|
||||||
@ -59,7 +90,7 @@ const confirmText = usePriorityValue('confirmText', props, state);
|
|||||||
"
|
"
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<SheetTitle v-if="title">
|
<SheetTitle v-if="title" class="text-left">
|
||||||
<slot name="title">
|
<slot name="title">
|
||||||
{{ title }}
|
{{ title }}
|
||||||
|
|
||||||
@ -111,22 +142,17 @@ const confirmText = usePriorityValue('confirmText', props, state);
|
|||||||
|
|
||||||
<SheetFooter
|
<SheetFooter
|
||||||
v-if="showFooter"
|
v-if="showFooter"
|
||||||
class="w-full items-center border-t p-2 px-3"
|
class="w-full flex-row items-center justify-end border-t p-2 px-3"
|
||||||
>
|
>
|
||||||
<slot name="prepend-footer"></slot>
|
<slot name="prepend-footer"></slot>
|
||||||
<slot name="footer">
|
<slot name="footer">
|
||||||
<VbenButton
|
<VbenButton variant="ghost" @click="() => drawerApi?.onCancel()">
|
||||||
size="sm"
|
|
||||||
variant="ghost"
|
|
||||||
@click="() => drawerApi?.onCancel()"
|
|
||||||
>
|
|
||||||
<slot name="cancelText">
|
<slot name="cancelText">
|
||||||
{{ cancelText }}
|
{{ cancelText }}
|
||||||
</slot>
|
</slot>
|
||||||
</VbenButton>
|
</VbenButton>
|
||||||
<VbenButton
|
<VbenButton
|
||||||
:loading="confirmLoading"
|
:loading="confirmLoading"
|
||||||
size="sm"
|
|
||||||
@click="() => drawerApi?.onConfirm()"
|
@click="() => drawerApi?.onConfirm()"
|
||||||
>
|
>
|
||||||
<slot name="confirmText">
|
<slot name="confirmText">
|
||||||
|
@ -3,7 +3,7 @@ import type { ExtendedModalApi, ModalProps } from './modal';
|
|||||||
|
|
||||||
import { computed, nextTick, ref, watch } from 'vue';
|
import { computed, nextTick, ref, watch } from 'vue';
|
||||||
|
|
||||||
import { usePriorityValue } from '@vben-core/composables';
|
import { useIsMobile, usePriorityValue } from '@vben-core/composables';
|
||||||
import { Expand, Info, Shrink } from '@vben-core/icons';
|
import { Expand, Info, Shrink } from '@vben-core/icons';
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
@ -46,6 +46,7 @@ const dialogRef = ref();
|
|||||||
const headerRef = ref();
|
const headerRef = ref();
|
||||||
const footerRef = ref();
|
const footerRef = ref();
|
||||||
|
|
||||||
|
const { isMobile } = useIsMobile();
|
||||||
// const { height: headerHeight } = useElementSize(headerRef);
|
// const { height: headerHeight } = useElementSize(headerRef);
|
||||||
// const { height: footerHeight } = useElementSize(footerRef);
|
// const { height: footerHeight } = useElementSize(footerRef);
|
||||||
const state = props.modalApi?.useStore?.();
|
const state = props.modalApi?.useStore?.();
|
||||||
@ -66,7 +67,11 @@ const draggable = usePriorityValue('draggable', props, state);
|
|||||||
const fullscreenButton = usePriorityValue('fullscreenButton', props, state);
|
const fullscreenButton = usePriorityValue('fullscreenButton', props, state);
|
||||||
const closeOnClickModal = usePriorityValue('closeOnClickModal', props, state);
|
const closeOnClickModal = usePriorityValue('closeOnClickModal', props, state);
|
||||||
const closeOnPressEscape = usePriorityValue('closeOnPressEscape', props, state);
|
const closeOnPressEscape = usePriorityValue('closeOnPressEscape', props, state);
|
||||||
const shouldDraggable = computed(() => draggable.value && !fullscreen.value);
|
|
||||||
|
const shouldFullscreen = computed(() => fullscreen.value || isMobile.value);
|
||||||
|
const shouldDraggable = computed(
|
||||||
|
() => draggable.value && !shouldFullscreen.value,
|
||||||
|
);
|
||||||
|
|
||||||
const { dragging } = useModalDraggable(dialogRef, headerRef, shouldDraggable);
|
const { dragging } = useModalDraggable(dialogRef, headerRef, shouldDraggable);
|
||||||
|
|
||||||
@ -114,6 +119,14 @@ function escapeKeyDown(e: KeyboardEvent) {
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// pointer-down-outside
|
||||||
|
function pointerDownOutside(e: Event) {
|
||||||
|
const target = e.target as HTMLElement;
|
||||||
|
const isDismissableModal = !!target?.dataset.dismissableModal;
|
||||||
|
if (!closeOnClickModal.value || !isDismissableModal) {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<Dialog
|
<Dialog
|
||||||
@ -133,8 +146,8 @@ function escapeKeyDown(e: KeyboardEvent) {
|
|||||||
props.class,
|
props.class,
|
||||||
{
|
{
|
||||||
'left-0 top-0 size-full max-h-full !translate-x-0 !translate-y-0':
|
'left-0 top-0 size-full max-h-full !translate-x-0 !translate-y-0':
|
||||||
fullscreen,
|
shouldFullscreen,
|
||||||
'top-1/2 -translate-y-1/2': centered && !fullscreen,
|
'top-1/2 -translate-y-1/2': centered && !shouldFullscreen,
|
||||||
'duration-300': !dragging,
|
'duration-300': !dragging,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@ -143,6 +156,7 @@ function escapeKeyDown(e: KeyboardEvent) {
|
|||||||
close-class="top-4"
|
close-class="top-4"
|
||||||
@escape-key-down="escapeKeyDown"
|
@escape-key-down="escapeKeyDown"
|
||||||
@interact-outside="interactOutside"
|
@interact-outside="interactOutside"
|
||||||
|
@pointer-down-outside="pointerDownOutside"
|
||||||
>
|
>
|
||||||
<DialogHeader
|
<DialogHeader
|
||||||
ref="headerRef"
|
ref="headerRef"
|
||||||
@ -156,7 +170,7 @@ function escapeKeyDown(e: KeyboardEvent) {
|
|||||||
)
|
)
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<DialogTitle v-if="title">
|
<DialogTitle v-if="title" class="text-left">
|
||||||
<slot name="title">
|
<slot name="title">
|
||||||
{{ title }}
|
{{ title }}
|
||||||
|
|
||||||
@ -191,7 +205,7 @@ function escapeKeyDown(e: KeyboardEvent) {
|
|||||||
|
|
||||||
<VbenIconButton
|
<VbenIconButton
|
||||||
v-if="fullscreenButton"
|
v-if="fullscreenButton"
|
||||||
class="hover:bg-accent hover:text-accent-foreground text-foreground/80 flex-center absolute right-10 top-4 size-6 rounded-full px-1 text-lg opacity-70 transition-opacity hover:opacity-100 focus:outline-none disabled:pointer-events-none"
|
class="hover:bg-accent hover:text-accent-foreground text-foreground/80 flex-center absolute right-10 top-4 hidden size-6 rounded-full px-1 text-lg opacity-70 transition-opacity hover:opacity-100 focus:outline-none disabled:pointer-events-none sm:block"
|
||||||
@click="handleFullscreen"
|
@click="handleFullscreen"
|
||||||
>
|
>
|
||||||
<Shrink v-if="fullscreen" class="size-3.5" />
|
<Shrink v-if="fullscreen" class="size-3.5" />
|
||||||
@ -201,22 +215,22 @@ function escapeKeyDown(e: KeyboardEvent) {
|
|||||||
<DialogFooter
|
<DialogFooter
|
||||||
v-if="showFooter"
|
v-if="showFooter"
|
||||||
ref="footerRef"
|
ref="footerRef"
|
||||||
:class="cn('items-center border-t p-2', props.footerClass)"
|
:class="
|
||||||
|
cn(
|
||||||
|
'flex-row items-center justify-end border-t p-2',
|
||||||
|
props.footerClass,
|
||||||
|
)
|
||||||
|
"
|
||||||
>
|
>
|
||||||
<slot name="prepend-footer"></slot>
|
<slot name="prepend-footer"></slot>
|
||||||
<slot name="footer">
|
<slot name="footer">
|
||||||
<VbenButton
|
<VbenButton variant="ghost" @click="() => modalApi?.onCancel()">
|
||||||
size="sm"
|
|
||||||
variant="ghost"
|
|
||||||
@click="() => modalApi?.onCancel()"
|
|
||||||
>
|
|
||||||
<slot name="cancelText">
|
<slot name="cancelText">
|
||||||
{{ cancelText }}
|
{{ cancelText }}
|
||||||
</slot>
|
</slot>
|
||||||
</VbenButton>
|
</VbenButton>
|
||||||
<VbenButton
|
<VbenButton
|
||||||
:loading="confirmLoading"
|
:loading="confirmLoading"
|
||||||
size="sm"
|
|
||||||
@click="() => modalApi?.onConfirm()"
|
@click="() => modalApi?.onConfirm()"
|
||||||
>
|
>
|
||||||
<slot name="confirmText">
|
<slot name="confirmText">
|
||||||
|
@ -94,7 +94,7 @@ async function checkProps(api: ExtendedModalApi, attrs: Record<string, any>) {
|
|||||||
if (stateKeys.has(attr)) {
|
if (stateKeys.has(attr)) {
|
||||||
// connectedComponent存在时,不要传入Modal的props,会造成复杂度提升,如果你需要修改Modal的props,请使用 useModal 或者api
|
// connectedComponent存在时,不要传入Modal的props,会造成复杂度提升,如果你需要修改Modal的props,请使用 useModal 或者api
|
||||||
console.warn(
|
console.warn(
|
||||||
`[Vben Modal]: When 'connectedComponent' exists, do not set props or slots '${attr}', which will increase complexity. If you need to modify the props of Modal, please use useModal or api.`,
|
`[Vben Modal]: When 'connectedComponent' exists, do not set props or slots '${attr}', which will increase complexity. If you need to modify the props of Modal, please use useVbenModal or api.`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,6 +45,7 @@ defineExpose({
|
|||||||
<DialogPortal>
|
<DialogPortal>
|
||||||
<DialogOverlay
|
<DialogOverlay
|
||||||
class="data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 bg-overlay fixed inset-0 z-[1000] backdrop-blur-sm"
|
class="data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 bg-overlay fixed inset-0 z-[1000] backdrop-blur-sm"
|
||||||
|
data-dismissable-modal="true"
|
||||||
@click="() => emits('close')"
|
@click="() => emits('close')"
|
||||||
/>
|
/>
|
||||||
<DialogContent
|
<DialogContent
|
||||||
|
@ -40,6 +40,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
|
|||||||
<DialogPortal>
|
<DialogPortal>
|
||||||
<DialogOverlay
|
<DialogOverlay
|
||||||
class="bg-overlay data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-[1000]"
|
class="bg-overlay data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-[1000]"
|
||||||
|
data-dismissable-modal="true"
|
||||||
/>
|
/>
|
||||||
<DialogContent
|
<DialogContent
|
||||||
:class="cn(sheetVariants({ side }), 'z-[1000]', props.class)"
|
:class="cn(sheetVariants({ side }), 'z-[1000]', props.class)"
|
||||||
|
@ -73,6 +73,7 @@ export function useTabsViewScroll(props: TabsProps) {
|
|||||||
resizeObserver = new ResizeObserver(
|
resizeObserver = new ResizeObserver(
|
||||||
useDebounceFn((_entries: ResizeObserverEntry[]) => {
|
useDebounceFn((_entries: ResizeObserverEntry[]) => {
|
||||||
calcShowScrollbarButton();
|
calcShowScrollbarButton();
|
||||||
|
scrollToActiveIntoView();
|
||||||
}, 100),
|
}, 100),
|
||||||
);
|
);
|
||||||
resizeObserver.observe(viewportEl);
|
resizeObserver.observe(viewportEl);
|
||||||
|
@ -1 +0,0 @@
|
|||||||
export * from './echarts';
|
|
@ -28,7 +28,7 @@ withDefaults(defineProps<Props>(), {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const accessStore = useAccessStore();
|
const accessStore = useAccessStore();
|
||||||
const { globalSearchShortcutKey } = usePreferences();
|
const { globalSearchShortcutKey, preferencesButtonPosition } = usePreferences();
|
||||||
const slots = useSlots();
|
const slots = useSlots();
|
||||||
const rightSlots = computed(() => {
|
const rightSlots = computed(() => {
|
||||||
const list = [{ index: 100, name: 'user-dropdown' }];
|
const list = [{ index: 100, name: 'user-dropdown' }];
|
||||||
@ -39,10 +39,7 @@ const rightSlots = computed(() => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (preferencesButtonPosition.value.header) {
|
||||||
preferences.app.enablePreferences &&
|
|
||||||
preferences.app.preferencesButtonPosition === 'header'
|
|
||||||
) {
|
|
||||||
list.push({
|
list.push({
|
||||||
index: 10,
|
index: 10,
|
||||||
name: 'preferences',
|
name: 'preferences',
|
||||||
@ -121,7 +118,7 @@ const leftSlots = computed(() => {
|
|||||||
<GlobalSearch
|
<GlobalSearch
|
||||||
:enable-shortcut-key="globalSearchShortcutKey"
|
:enable-shortcut-key="globalSearchShortcutKey"
|
||||||
:menus="accessStore.accessMenus"
|
:menus="accessStore.accessMenus"
|
||||||
class="mr-4"
|
class="mr-1 sm:mr-4"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -40,6 +40,7 @@ const {
|
|||||||
isMobile,
|
isMobile,
|
||||||
isSideMixedNav,
|
isSideMixedNav,
|
||||||
layout,
|
layout,
|
||||||
|
preferencesButtonPosition,
|
||||||
sidebarCollapsed,
|
sidebarCollapsed,
|
||||||
theme,
|
theme,
|
||||||
} = usePreferences();
|
} = usePreferences();
|
||||||
@ -326,12 +327,7 @@ const headerSlots = computed(() => {
|
|||||||
<slot v-if="lockStore.isLockScreen" name="lock-screen"></slot>
|
<slot v-if="lockStore.isLockScreen" name="lock-screen"></slot>
|
||||||
</Transition>
|
</Transition>
|
||||||
|
|
||||||
<template
|
<template v-if="preferencesButtonPosition.fixed">
|
||||||
v-if="
|
|
||||||
preferences.app.enablePreferences &&
|
|
||||||
preferences.app.preferencesButtonPosition === 'fixed'
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<Preferences
|
<Preferences
|
||||||
class="z-100 fixed bottom-20 right-0"
|
class="z-100 fixed bottom-20 right-0"
|
||||||
@clear-preferences-and-logout="clearPreferencesAndLogout"
|
@clear-preferences-and-logout="clearPreferencesAndLogout"
|
||||||
|
@ -127,7 +127,7 @@ onMounted(() => {
|
|||||||
@click="toggleOpen()"
|
@click="toggleOpen()"
|
||||||
>
|
>
|
||||||
<Search
|
<Search
|
||||||
class="text-muted-foreground group-hover:text-foreground size-3 group-hover:opacity-100"
|
class="text-muted-foreground group-hover:text-foreground size-4 group-hover:opacity-100"
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
class="text-muted-foreground group-hover:text-foreground hidden text-xs duration-300 md:block"
|
class="text-muted-foreground group-hover:text-foreground hidden text-xs duration-300 md:block"
|
||||||
|
@ -159,7 +159,7 @@ function toggleUnlockForm() {
|
|||||||
</transition>
|
</transition>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="enter-y absolute bottom-5 w-full text-center text-gray-300 xl:text-xl 2xl:text-3xl"
|
class="enter-y absolute bottom-5 w-full text-center xl:text-xl 2xl:text-3xl"
|
||||||
>
|
>
|
||||||
<div v-if="showUnlockForm" class="enter-x mb-2 text-3xl">
|
<div v-if="showUnlockForm" class="enter-x mb-2 text-3xl">
|
||||||
{{ hour }}:{{ minute }} <span class="text-lg">{{ meridiem }}</span>
|
{{ hour }}:{{ minute }} <span class="text-lg">{{ meridiem }}</span>
|
||||||
|
@ -24,6 +24,10 @@ const appPreferencesButtonPosition = defineModel<string>(
|
|||||||
);
|
);
|
||||||
|
|
||||||
const positionItems = computed((): SelectOption[] => [
|
const positionItems = computed((): SelectOption[] => [
|
||||||
|
{
|
||||||
|
label: $t('preferences.position.auto'),
|
||||||
|
value: 'auto',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: $t('preferences.position.header'),
|
label: $t('preferences.position.header'),
|
||||||
value: 'header',
|
value: 'header',
|
||||||
|
@ -55,7 +55,7 @@ const listen = computed(() => {
|
|||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<Drawer v-bind="attrs" v-on="listen" />
|
<Drawer v-bind="{ ...$attrs, ...attrs }" v-on="listen" />
|
||||||
|
|
||||||
<div @click="() => drawerApi.open()">
|
<div @click="() => drawerApi.open()">
|
||||||
<slot>
|
<slot>
|
||||||
|
28
packages/effects/plugins/README.md
Normal file
28
packages/effects/plugins/README.md
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# @vben/plugins
|
||||||
|
|
||||||
|
该目录用于存放项目中集成的第三方库及其相关插件。每个插件都包含了可重用的逻辑、配置和组件,方便在项目中进行统一管理和调用。
|
||||||
|
|
||||||
|
## 注意
|
||||||
|
|
||||||
|
所有的第三方插件都必须以 `subpath` 形式引入,例:
|
||||||
|
|
||||||
|
以 `echarts` 为例,引入方式如下:
|
||||||
|
|
||||||
|
**packages.json**
|
||||||
|
|
||||||
|
```json
|
||||||
|
"exports": {
|
||||||
|
"./echarts": {
|
||||||
|
"types": "./src/echarts/index.ts",
|
||||||
|
"default": "./src/echarts/index.ts"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**使用方式**
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { useEcharts } from '@vben/plugins/echarts';
|
||||||
|
```
|
||||||
|
|
||||||
|
这样做的好处是,应用可以自行选择是否使用插件,而不会因为插件的引入及副作用而导致打包体积增大,只引入需要的插件即可。
|
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "@vben/chart-ui",
|
"name": "@vben/plugins",
|
||||||
"version": "5.1.2",
|
"version": "5.1.2",
|
||||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git+https://github.com/vbenjs/vue-vben-admin.git",
|
"url": "git+https://github.com/vbenjs/vue-vben-admin.git",
|
||||||
"directory": "packages/effects/chart-ui"
|
"directory": "packages/effects/plugins"
|
||||||
},
|
},
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
@ -14,9 +14,9 @@
|
|||||||
"**/*.css"
|
"**/*.css"
|
||||||
],
|
],
|
||||||
"exports": {
|
"exports": {
|
||||||
".": {
|
"./echarts": {
|
||||||
"types": "./src/index.ts",
|
"types": "./src/echarts/index.ts",
|
||||||
"default": "./src/index.ts"
|
"default": "./src/echarts/index.ts"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
@ -5,11 +5,12 @@ import type EchartsUI from './echarts-ui.vue';
|
|||||||
import type { Ref } from 'vue';
|
import type { Ref } from 'vue';
|
||||||
import { computed, nextTick, watch } from 'vue';
|
import { computed, nextTick, watch } from 'vue';
|
||||||
|
|
||||||
import { preferences, usePreferences } from '@vben/preferences';
|
import { usePreferences } from '@vben/preferences';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
tryOnUnmounted,
|
tryOnUnmounted,
|
||||||
useDebounceFn,
|
useDebounceFn,
|
||||||
|
useResizeObserver,
|
||||||
useTimeoutFn,
|
useTimeoutFn,
|
||||||
useWindowSize,
|
useWindowSize,
|
||||||
} from '@vueuse/core';
|
} from '@vueuse/core';
|
||||||
@ -86,6 +87,8 @@ function useEcharts(chartRef: Ref<EchartsUIType>) {
|
|||||||
resizeHandler?.();
|
resizeHandler?.();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useResizeObserver(chartRef as never, resizeHandler);
|
||||||
|
|
||||||
watch(isDark, () => {
|
watch(isDark, () => {
|
||||||
if (chartInstance) {
|
if (chartInstance) {
|
||||||
chartInstance.dispose();
|
chartInstance.dispose();
|
||||||
@ -95,21 +98,6 @@ function useEcharts(chartRef: Ref<EchartsUIType>) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
watch(
|
|
||||||
[
|
|
||||||
() => preferences.sidebar.collapsed,
|
|
||||||
() => preferences.sidebar.extraCollapse,
|
|
||||||
() => preferences.sidebar.hidden,
|
|
||||||
() => preferences.app.contentCompact,
|
|
||||||
],
|
|
||||||
() => {
|
|
||||||
// 折叠动画200ms
|
|
||||||
setTimeout(() => {
|
|
||||||
resize();
|
|
||||||
}, 200);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
tryOnUnmounted(() => {
|
tryOnUnmounted(() => {
|
||||||
// 销毁实例,释放资源
|
// 销毁实例,释放资源
|
||||||
chartInstance?.dispose();
|
chartInstance?.dispose();
|
@ -182,6 +182,7 @@
|
|||||||
"position": {
|
"position": {
|
||||||
"title": "Preferences Postion",
|
"title": "Preferences Postion",
|
||||||
"header": "Header",
|
"header": "Header",
|
||||||
|
"auto": "Auto",
|
||||||
"fixed": "Fixed"
|
"fixed": "Fixed"
|
||||||
},
|
},
|
||||||
"sidebar": {
|
"sidebar": {
|
||||||
|
@ -182,6 +182,7 @@
|
|||||||
"position": {
|
"position": {
|
||||||
"title": "偏好设置位置",
|
"title": "偏好设置位置",
|
||||||
"header": "顶栏",
|
"header": "顶栏",
|
||||||
|
"auto": "自动",
|
||||||
"fixed": "固定"
|
"fixed": "固定"
|
||||||
},
|
},
|
||||||
"sidebar": {
|
"sidebar": {
|
||||||
|
6
packages/utils/src/helpers/get-popup-container.ts
Normal file
6
packages/utils/src/helpers/get-popup-container.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
/**
|
||||||
|
* Returns the parent node of the given element or the document body if the element is not provided.it
|
||||||
|
*/
|
||||||
|
export function getPopupContainer(node?: HTMLElement): HTMLElement {
|
||||||
|
return (node?.parentNode as HTMLElement) ?? document.body;
|
||||||
|
}
|
@ -2,6 +2,7 @@ export * from './find-menu-by-path';
|
|||||||
export * from './generate-menus';
|
export * from './generate-menus';
|
||||||
export * from './generate-routes-backend';
|
export * from './generate-routes-backend';
|
||||||
export * from './generate-routes-frontend';
|
export * from './generate-routes-frontend';
|
||||||
|
export * from './get-popup-container';
|
||||||
export * from './merge-route-modules';
|
export * from './merge-route-modules';
|
||||||
export * from './reset-routes';
|
export * from './reset-routes';
|
||||||
export * from './unmount-global-loading';
|
export * from './unmount-global-loading';
|
||||||
|
@ -27,13 +27,13 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vben/access": "workspace:*",
|
"@vben/access": "workspace:*",
|
||||||
"@vben/chart-ui": "workspace:*",
|
|
||||||
"@vben/common-ui": "workspace:*",
|
"@vben/common-ui": "workspace:*",
|
||||||
"@vben/constants": "workspace:*",
|
"@vben/constants": "workspace:*",
|
||||||
"@vben/hooks": "workspace:*",
|
"@vben/hooks": "workspace:*",
|
||||||
"@vben/icons": "workspace:*",
|
"@vben/icons": "workspace:*",
|
||||||
"@vben/layouts": "workspace:*",
|
"@vben/layouts": "workspace:*",
|
||||||
"@vben/locales": "workspace:*",
|
"@vben/locales": "workspace:*",
|
||||||
|
"@vben/plugins": "workspace:*",
|
||||||
"@vben/preferences": "workspace:*",
|
"@vben/preferences": "workspace:*",
|
||||||
"@vben/request": "workspace:*",
|
"@vben/request": "workspace:*",
|
||||||
"@vben/stores": "workspace:*",
|
"@vben/stores": "workspace:*",
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
|
|
||||||
import { EchartsUI, type EchartsUIType, useEcharts } from '@vben/chart-ui';
|
import {
|
||||||
|
EchartsUI,
|
||||||
|
type EchartsUIType,
|
||||||
|
useEcharts,
|
||||||
|
} from '@vben/plugins/echarts';
|
||||||
|
|
||||||
const chartRef = ref<EchartsUIType>();
|
const chartRef = ref<EchartsUIType>();
|
||||||
const { renderEcharts } = useEcharts(chartRef);
|
const { renderEcharts } = useEcharts(chartRef);
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
|
|
||||||
import { EchartsUI, type EchartsUIType, useEcharts } from '@vben/chart-ui';
|
import {
|
||||||
|
EchartsUI,
|
||||||
|
type EchartsUIType,
|
||||||
|
useEcharts,
|
||||||
|
} from '@vben/plugins/echarts';
|
||||||
|
|
||||||
const chartRef = ref<EchartsUIType>();
|
const chartRef = ref<EchartsUIType>();
|
||||||
const { renderEcharts } = useEcharts(chartRef);
|
const { renderEcharts } = useEcharts(chartRef);
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
|
|
||||||
import { EchartsUI, type EchartsUIType, useEcharts } from '@vben/chart-ui';
|
import {
|
||||||
|
EchartsUI,
|
||||||
|
type EchartsUIType,
|
||||||
|
useEcharts,
|
||||||
|
} from '@vben/plugins/echarts';
|
||||||
|
|
||||||
const chartRef = ref<EchartsUIType>();
|
const chartRef = ref<EchartsUIType>();
|
||||||
const { renderEcharts } = useEcharts(chartRef);
|
const { renderEcharts } = useEcharts(chartRef);
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
|
|
||||||
import { EchartsUI, type EchartsUIType, useEcharts } from '@vben/chart-ui';
|
import {
|
||||||
|
EchartsUI,
|
||||||
|
type EchartsUIType,
|
||||||
|
useEcharts,
|
||||||
|
} from '@vben/plugins/echarts';
|
||||||
|
|
||||||
const chartRef = ref<EchartsUIType>();
|
const chartRef = ref<EchartsUIType>();
|
||||||
const { renderEcharts } = useEcharts(chartRef);
|
const { renderEcharts } = useEcharts(chartRef);
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
|
|
||||||
import { EchartsUI, type EchartsUIType, useEcharts } from '@vben/chart-ui';
|
import {
|
||||||
|
EchartsUI,
|
||||||
|
type EchartsUIType,
|
||||||
|
useEcharts,
|
||||||
|
} from '@vben/plugins/echarts';
|
||||||
|
|
||||||
const chartRef = ref<EchartsUIType>();
|
const chartRef = ref<EchartsUIType>();
|
||||||
const { renderEcharts } = useEcharts(chartRef);
|
const { renderEcharts } = useEcharts(chartRef);
|
||||||
|
@ -138,9 +138,6 @@ importers:
|
|||||||
'@vben/access':
|
'@vben/access':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../../packages/effects/access
|
version: link:../../packages/effects/access
|
||||||
'@vben/chart-ui':
|
|
||||||
specifier: workspace:*
|
|
||||||
version: link:../../packages/effects/chart-ui
|
|
||||||
'@vben/common-ui':
|
'@vben/common-ui':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../../packages/effects/common-ui
|
version: link:../../packages/effects/common-ui
|
||||||
@ -159,6 +156,9 @@ importers:
|
|||||||
'@vben/locales':
|
'@vben/locales':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../../packages/locales
|
version: link:../../packages/locales
|
||||||
|
'@vben/plugins':
|
||||||
|
specifier: workspace:*
|
||||||
|
version: link:../../packages/effects/plugins
|
||||||
'@vben/preferences':
|
'@vben/preferences':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../../packages/preferences
|
version: link:../../packages/preferences
|
||||||
@ -226,9 +226,6 @@ importers:
|
|||||||
'@vben/access':
|
'@vben/access':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../../packages/effects/access
|
version: link:../../packages/effects/access
|
||||||
'@vben/chart-ui':
|
|
||||||
specifier: workspace:*
|
|
||||||
version: link:../../packages/effects/chart-ui
|
|
||||||
'@vben/common-ui':
|
'@vben/common-ui':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../../packages/effects/common-ui
|
version: link:../../packages/effects/common-ui
|
||||||
@ -247,6 +244,9 @@ importers:
|
|||||||
'@vben/locales':
|
'@vben/locales':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../../packages/locales
|
version: link:../../packages/locales
|
||||||
|
'@vben/plugins':
|
||||||
|
specifier: workspace:*
|
||||||
|
version: link:../../packages/effects/plugins
|
||||||
'@vben/preferences':
|
'@vben/preferences':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../../packages/preferences
|
version: link:../../packages/preferences
|
||||||
@ -293,9 +293,6 @@ importers:
|
|||||||
'@vben/access':
|
'@vben/access':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../../packages/effects/access
|
version: link:../../packages/effects/access
|
||||||
'@vben/chart-ui':
|
|
||||||
specifier: workspace:*
|
|
||||||
version: link:../../packages/effects/chart-ui
|
|
||||||
'@vben/common-ui':
|
'@vben/common-ui':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../../packages/effects/common-ui
|
version: link:../../packages/effects/common-ui
|
||||||
@ -314,6 +311,9 @@ importers:
|
|||||||
'@vben/locales':
|
'@vben/locales':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../../packages/locales
|
version: link:../../packages/locales
|
||||||
|
'@vben/plugins':
|
||||||
|
specifier: workspace:*
|
||||||
|
version: link:../../packages/effects/plugins
|
||||||
'@vben/preferences':
|
'@vben/preferences':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../../packages/preferences
|
version: link:../../packages/preferences
|
||||||
@ -928,21 +928,6 @@ importers:
|
|||||||
specifier: 3.4.38
|
specifier: 3.4.38
|
||||||
version: 3.4.38(typescript@5.5.4)
|
version: 3.4.38(typescript@5.5.4)
|
||||||
|
|
||||||
packages/effects/chart-ui:
|
|
||||||
dependencies:
|
|
||||||
'@vben/preferences':
|
|
||||||
specifier: workspace:*
|
|
||||||
version: link:../../preferences
|
|
||||||
'@vueuse/core':
|
|
||||||
specifier: ^11.0.1
|
|
||||||
version: 11.0.1(vue@3.4.38(typescript@5.5.4))
|
|
||||||
echarts:
|
|
||||||
specifier: ^5.5.1
|
|
||||||
version: 5.5.1
|
|
||||||
vue:
|
|
||||||
specifier: 3.4.38
|
|
||||||
version: 3.4.38(typescript@5.5.4)
|
|
||||||
|
|
||||||
packages/effects/common-ui:
|
packages/effects/common-ui:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vben-core/popup-ui':
|
'@vben-core/popup-ui':
|
||||||
@ -1061,6 +1046,21 @@ importers:
|
|||||||
specifier: ^4.4.3
|
specifier: ^4.4.3
|
||||||
version: 4.4.3(vue@3.4.38(typescript@5.5.4))
|
version: 4.4.3(vue@3.4.38(typescript@5.5.4))
|
||||||
|
|
||||||
|
packages/effects/plugins:
|
||||||
|
dependencies:
|
||||||
|
'@vben/preferences':
|
||||||
|
specifier: workspace:*
|
||||||
|
version: link:../../preferences
|
||||||
|
'@vueuse/core':
|
||||||
|
specifier: ^11.0.1
|
||||||
|
version: 11.0.1(vue@3.4.38(typescript@5.5.4))
|
||||||
|
echarts:
|
||||||
|
specifier: ^5.5.1
|
||||||
|
version: 5.5.1
|
||||||
|
vue:
|
||||||
|
specifier: 3.4.38
|
||||||
|
version: 3.4.38(typescript@5.5.4)
|
||||||
|
|
||||||
packages/effects/request:
|
packages/effects/request:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vben/locales':
|
'@vben/locales':
|
||||||
@ -1160,9 +1160,6 @@ importers:
|
|||||||
'@vben/access':
|
'@vben/access':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../packages/effects/access
|
version: link:../packages/effects/access
|
||||||
'@vben/chart-ui':
|
|
||||||
specifier: workspace:*
|
|
||||||
version: link:../packages/effects/chart-ui
|
|
||||||
'@vben/common-ui':
|
'@vben/common-ui':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../packages/effects/common-ui
|
version: link:../packages/effects/common-ui
|
||||||
@ -1181,6 +1178,9 @@ importers:
|
|||||||
'@vben/locales':
|
'@vben/locales':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../packages/locales
|
version: link:../packages/locales
|
||||||
|
'@vben/plugins':
|
||||||
|
specifier: workspace:*
|
||||||
|
version: link:../packages/effects/plugins
|
||||||
'@vben/preferences':
|
'@vben/preferences':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../packages/preferences
|
version: link:../packages/preferences
|
||||||
|
@ -104,10 +104,6 @@
|
|||||||
"name": "@vben/access",
|
"name": "@vben/access",
|
||||||
"path": "packages/effects/access",
|
"path": "packages/effects/access",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "@vben/chart-ui",
|
|
||||||
"path": "packages/effects/chart-ui",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "@vben/common-ui",
|
"name": "@vben/common-ui",
|
||||||
"path": "packages/effects/common-ui",
|
"path": "packages/effects/common-ui",
|
||||||
@ -120,6 +116,10 @@
|
|||||||
"name": "@vben/layouts",
|
"name": "@vben/layouts",
|
||||||
"path": "packages/effects/layouts",
|
"path": "packages/effects/layouts",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "@vben/plugins",
|
||||||
|
"path": "packages/effects/plugins",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "@vben/request",
|
"name": "@vben/request",
|
||||||
"path": "packages/effects/request",
|
"path": "packages/effects/request",
|
||||||
|
3
vitest.workspace.ts
Normal file
3
vitest.workspace.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import { defineWorkspace } from 'vitest/config';
|
||||||
|
|
||||||
|
export default defineWorkspace(['vitest.config.ts']);
|
Loading…
Reference in New Issue
Block a user