fix:联调权限接口

This commit is contained in:
liangdong
2026-01-13 18:32:56 +08:00
parent c6a4604d1f
commit 05496ae4c4
28 changed files with 1234 additions and 382 deletions

86
components.d.ts vendored
View File

@@ -5,6 +5,7 @@
// ------ // ------
// Generated by unplugin-vue-components // Generated by unplugin-vue-components
// Read more: https://github.com/vuejs/core/pull/3399 // Read more: https://github.com/vuejs/core/pull/3399
import { GlobalComponents } from 'vue'
export {} export {}
@@ -63,6 +64,7 @@ declare module 'vue' {
ElSwitch: typeof import('element-plus/es')['ElSwitch'] ElSwitch: typeof import('element-plus/es')['ElSwitch']
ElTable: typeof import('element-plus/es')['ElTable'] ElTable: typeof import('element-plus/es')['ElTable']
ElTableColumn: typeof import('element-plus/es')['ElTableColumn'] ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
ElTableV2: typeof import('element-plus/es')['ElTableV2']
ElTabPane: typeof import('element-plus/es')['ElTabPane'] ElTabPane: typeof import('element-plus/es')['ElTabPane']
ElTabs: typeof import('element-plus/es')['ElTabs'] ElTabs: typeof import('element-plus/es')['ElTabs']
ElTag: typeof import('element-plus/es')['ElTag'] ElTag: typeof import('element-plus/es')['ElTag']
@@ -79,6 +81,7 @@ declare module 'vue' {
OverflowTabs: typeof import('./src/components/overflowTabs/index.vue')['default'] OverflowTabs: typeof import('./src/components/overflowTabs/index.vue')['default']
PageForm: typeof import('./src/components/pageForm/index.vue')['default'] PageForm: typeof import('./src/components/pageForm/index.vue')['default']
ProTable: typeof import('./src/components/proTable/index.vue')['default'] ProTable: typeof import('./src/components/proTable/index.vue')['default']
ProTablev2: typeof import('./src/components/proTable/proTablev2.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink'] RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView'] RouterView: typeof import('vue-router')['RouterView']
SopNode: typeof import('./src/components/nodeFlow/sopNode.vue')['default'] SopNode: typeof import('./src/components/nodeFlow/sopNode.vue')['default']
@@ -94,3 +97,86 @@ declare module 'vue' {
vLoading: typeof import('element-plus/es')['ElLoadingDirective'] vLoading: typeof import('element-plus/es')['ElLoadingDirective']
} }
} }
// For TSX support
declare global {
const AutoTooltip: typeof import('./src/components/autoTooltip/index.vue')['default']
const CardItem: typeof import('./src/components/cardItem/index.vue')['default']
const CollapseHeader: typeof import('./src/components/collapseHeader/index.vue')['default']
const Comment: typeof import('./src/components/comment/index.vue')['default']
const CommonFilter: typeof import('./src/components/commonFilter/index.vue')['default']
const DynamicSvgIcon: typeof import('./src/components/dynamicSvgIcon/index.vue')['default']
const ElAside: typeof import('element-plus/es')['ElAside']
const ElAvatar: typeof import('element-plus/es')['ElAvatar']
const ElBadge: typeof import('element-plus/es')['ElBadge']
const ElButton: typeof import('element-plus/es')['ElButton']
const ElCard: typeof import('element-plus/es')['ElCard']
const ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
const ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup']
const ElCol: typeof import('element-plus/es')['ElCol']
const ElContainer: typeof import('element-plus/es')['ElContainer']
const ElDatePick: typeof import('element-plus/es')['ElDatePick']
const ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
const ElDescriptions: typeof import('element-plus/es')['ElDescriptions']
const ElDescriptionsItem: typeof import('element-plus/es')['ElDescriptionsItem']
const ElDialog: typeof import('element-plus/es')['ElDialog']
const ElDivider: typeof import('element-plus/es')['ElDivider']
const ElDrawer: typeof import('element-plus/es')['ElDrawer']
const ElDropdown: typeof import('element-plus/es')['ElDropdown']
const ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
const ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
const ElEmpty: typeof import('element-plus/es')['ElEmpty']
const ElForm: typeof import('element-plus/es')['ElForm']
const ElFormItem: typeof import('element-plus/es')['ElFormItem']
const ElHeader: typeof import('element-plus/es')['ElHeader']
const ElIcon: typeof import('element-plus/es')['ElIcon']
const ElInput: typeof import('element-plus/es')['ElInput']
const ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
const ElLink: typeof import('element-plus/es')['ElLink']
const ElMain: typeof import('element-plus/es')['ElMain']
const ElMention: typeof import('element-plus/es')['ElMention']
const ElMenu: typeof import('element-plus/es')['ElMenu']
const ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
const ElOption: typeof import('element-plus/es')['ElOption']
const ElPagination: typeof import('element-plus/es')['ElPagination']
const ElPopover: typeof import('element-plus/es')['ElPopover']
const ElRadio: typeof import('element-plus/es')['ElRadio']
const ElRadioButton: typeof import('element-plus/es')['ElRadioButton']
const ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
const ElRow: typeof import('element-plus/es')['ElRow']
const ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
const ElSelect: typeof import('element-plus/es')['ElSelect']
const ElSkeleton: typeof import('element-plus/es')['ElSkeleton']
const ElSkeletonItem: typeof import('element-plus/es')['ElSkeletonItem']
const ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
const ElSwitch: typeof import('element-plus/es')['ElSwitch']
const ElTable: typeof import('element-plus/es')['ElTable']
const ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
const ElTableV2: typeof import('element-plus/es')['ElTableV2']
const ElTabPane: typeof import('element-plus/es')['ElTabPane']
const ElTabs: typeof import('element-plus/es')['ElTabs']
const ElTag: typeof import('element-plus/es')['ElTag']
const ElTimeline: typeof import('element-plus/es')['ElTimeline']
const ElTimelineItem: typeof import('element-plus/es')['ElTimelineItem']
const ElTooltip: typeof import('element-plus/es')['ElTooltip']
const ElTree: typeof import('element-plus/es')['ElTree']
const EmojiPicker: typeof import('./src/components/comment/emojiPicker.vue')['default']
const GlobaIcon: typeof import('./src/components/globaIcon/index.vue')['default']
const GlobalIcon: typeof import('./src/components/GlobalIcon/index.vue')['default']
const MemberSelector: typeof import('./src/components/memberSelector/index.vue')['default']
const NameAvatar: typeof import('./src/components/nameAvatar/index.vue')['default']
const NodeFlow: typeof import('./src/components/nodeFlow/index.vue')['default']
const OverflowTabs: typeof import('./src/components/overflowTabs/index.vue')['default']
const PageForm: typeof import('./src/components/pageForm/index.vue')['default']
const ProTable: typeof import('./src/components/proTable/index.vue')['default']
const ProTablev2: typeof import('./src/components/proTable/proTablev2.vue')['default']
const RouterLink: typeof import('vue-router')['RouterLink']
const RouterView: typeof import('vue-router')['RouterView']
const SopNode: typeof import('./src/components/nodeFlow/sopNode.vue')['default']
const StageBreadcrumbs: typeof import('./src/components/stageBreadcrumbs/index.vue')['default']
const StandardMenu: typeof import('./src/components/standardMenu/index.vue')['default']
const StandMenu: typeof import('./src/components/standMenu/index.vue')['default']
const UserSelector: typeof import('./src/components/userSelector/index.vue')['default']
const Xxx: typeof import('./src/components/comment/xxx.vue')['default']
const Xxxx: typeof import('./src/components/xxxx/index.vue')['default']
}

View File

@@ -11,6 +11,7 @@
"dependencies": { "dependencies": {
"@element-plus/icons-vue": "^2.3.2", "@element-plus/icons-vue": "^2.3.2",
"@micro-zoe/micro-app": "^1.0.0-rc.28", "@micro-zoe/micro-app": "^1.0.0-rc.28",
"@vitejs/plugin-vue-jsx": "^5.1.3",
"@vue-flow/core": "^1.48.1", "@vue-flow/core": "^1.48.1",
"element-plus": "^2.13.0", "element-plus": "^2.13.0",
"pinia": "^3.0.4", "pinia": "^3.0.4",

467
pnpm-lock.yaml generated
View File

@@ -14,6 +14,9 @@ importers:
'@micro-zoe/micro-app': '@micro-zoe/micro-app':
specifier: ^1.0.0-rc.28 specifier: ^1.0.0-rc.28
version: 1.0.0-rc.28 version: 1.0.0-rc.28
'@vitejs/plugin-vue-jsx':
specifier: ^5.1.3
version: 5.1.3(vite@7.3.0(@types/node@24.10.4)(sass@1.97.1))(vue@3.5.26(typescript@5.9.3))
'@vue-flow/core': '@vue-flow/core':
specifier: ^1.48.1 specifier: ^1.48.1
version: 1.48.1(vue@3.5.26(typescript@5.9.3)) version: 1.48.1(vue@3.5.26(typescript@5.9.3))
@@ -65,7 +68,7 @@ importers:
version: 20.3.0(@vueuse/core@10.11.1(vue@3.5.26(typescript@5.9.3))) version: 20.3.0(@vueuse/core@10.11.1(vue@3.5.26(typescript@5.9.3)))
unplugin-vue-components: unplugin-vue-components:
specifier: ^30.0.0 specifier: ^30.0.0
version: 30.0.0(@babel/parser@7.28.5)(vue@3.5.26(typescript@5.9.3)) version: 30.0.0(@babel/parser@7.28.6)(vue@3.5.26(typescript@5.9.3))
vite: vite:
specifier: ^7.2.4 specifier: ^7.2.4
version: 7.3.0(@types/node@24.10.4)(sass@1.97.1) version: 7.3.0(@types/node@24.10.4)(sass@1.97.1)
@@ -75,6 +78,72 @@ importers:
packages: packages:
'@babel/code-frame@7.28.6':
resolution: {integrity: sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==}
engines: {node: '>=6.9.0'}
'@babel/compat-data@7.28.6':
resolution: {integrity: sha512-2lfu57JtzctfIrcGMz992hyLlByuzgIk58+hhGCxjKZ3rWI82NnVLjXcaTqkI2NvlcvOskZaiZ5kjUALo3Lpxg==}
engines: {node: '>=6.9.0'}
'@babel/core@7.28.6':
resolution: {integrity: sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==}
engines: {node: '>=6.9.0'}
'@babel/generator@7.28.6':
resolution: {integrity: sha512-lOoVRwADj8hjf7al89tvQ2a1lf53Z+7tiXMgpZJL3maQPDxh0DgLMN62B2MKUOFcoodBHLMbDM6WAbKgNy5Suw==}
engines: {node: '>=6.9.0'}
'@babel/helper-annotate-as-pure@7.27.3':
resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==}
engines: {node: '>=6.9.0'}
'@babel/helper-compilation-targets@7.28.6':
resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==}
engines: {node: '>=6.9.0'}
'@babel/helper-create-class-features-plugin@7.28.6':
resolution: {integrity: sha512-dTOdvsjnG3xNT9Y0AUg1wAl38y+4Rl4sf9caSQZOXdNqVn+H+HbbJ4IyyHaIqNR6SW9oJpA/RuRjsjCw2IdIow==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0
'@babel/helper-globals@7.28.0':
resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==}
engines: {node: '>=6.9.0'}
'@babel/helper-member-expression-to-functions@7.28.5':
resolution: {integrity: sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==}
engines: {node: '>=6.9.0'}
'@babel/helper-module-imports@7.28.6':
resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==}
engines: {node: '>=6.9.0'}
'@babel/helper-module-transforms@7.28.6':
resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0
'@babel/helper-optimise-call-expression@7.27.1':
resolution: {integrity: sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==}
engines: {node: '>=6.9.0'}
'@babel/helper-plugin-utils@7.28.6':
resolution: {integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==}
engines: {node: '>=6.9.0'}
'@babel/helper-replace-supers@7.28.6':
resolution: {integrity: sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0
'@babel/helper-skip-transparent-expression-wrappers@7.27.1':
resolution: {integrity: sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==}
engines: {node: '>=6.9.0'}
'@babel/helper-string-parser@7.27.1': '@babel/helper-string-parser@7.27.1':
resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
@@ -83,15 +152,58 @@ packages:
resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
'@babel/helper-validator-option@7.27.1':
resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==}
engines: {node: '>=6.9.0'}
'@babel/helpers@7.28.6':
resolution: {integrity: sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==}
engines: {node: '>=6.9.0'}
'@babel/parser@7.28.5': '@babel/parser@7.28.5':
resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==} resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==}
engines: {node: '>=6.0.0'} engines: {node: '>=6.0.0'}
hasBin: true hasBin: true
'@babel/parser@7.28.6':
resolution: {integrity: sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==}
engines: {node: '>=6.0.0'}
hasBin: true
'@babel/plugin-syntax-jsx@7.28.6':
resolution: {integrity: sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
'@babel/plugin-syntax-typescript@7.28.6':
resolution: {integrity: sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
'@babel/plugin-transform-typescript@7.28.6':
resolution: {integrity: sha512-0YWL2RFxOqEm9Efk5PvreamxPME8OyY0wM5wh5lHjF+VtVhdneCWGzZeSqzOfiobVqQaNCd2z0tQvnI9DaPWPw==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
'@babel/template@7.28.6':
resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==}
engines: {node: '>=6.9.0'}
'@babel/traverse@7.28.6':
resolution: {integrity: sha512-fgWX62k02qtjqdSNTAGxmKYY/7FSL9WAS1o2Hu5+I5m9T0yxZzr4cnrfXQ/MX0rIifthCSs6FKTlzYbJcPtMNg==}
engines: {node: '>=6.9.0'}
'@babel/types@7.28.5': '@babel/types@7.28.5':
resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
'@babel/types@7.28.6':
resolution: {integrity: sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==}
engines: {node: '>=6.9.0'}
'@ctrl/tinycolor@3.6.1': '@ctrl/tinycolor@3.6.1':
resolution: {integrity: sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==} resolution: {integrity: sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==}
engines: {node: '>=10'} engines: {node: '>=10'}
@@ -326,42 +438,36 @@ packages:
engines: {node: '>= 10.0.0'} engines: {node: '>= 10.0.0'}
cpu: [arm] cpu: [arm]
os: [linux] os: [linux]
libc: [glibc]
'@parcel/watcher-linux-arm-musl@2.5.1': '@parcel/watcher-linux-arm-musl@2.5.1':
resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==} resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==}
engines: {node: '>= 10.0.0'} engines: {node: '>= 10.0.0'}
cpu: [arm] cpu: [arm]
os: [linux] os: [linux]
libc: [musl]
'@parcel/watcher-linux-arm64-glibc@2.5.1': '@parcel/watcher-linux-arm64-glibc@2.5.1':
resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==} resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==}
engines: {node: '>= 10.0.0'} engines: {node: '>= 10.0.0'}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
libc: [glibc]
'@parcel/watcher-linux-arm64-musl@2.5.1': '@parcel/watcher-linux-arm64-musl@2.5.1':
resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==} resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==}
engines: {node: '>= 10.0.0'} engines: {node: '>= 10.0.0'}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
libc: [musl]
'@parcel/watcher-linux-x64-glibc@2.5.1': '@parcel/watcher-linux-x64-glibc@2.5.1':
resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==} resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==}
engines: {node: '>= 10.0.0'} engines: {node: '>= 10.0.0'}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
libc: [glibc]
'@parcel/watcher-linux-x64-musl@2.5.1': '@parcel/watcher-linux-x64-musl@2.5.1':
resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==} resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==}
engines: {node: '>= 10.0.0'} engines: {node: '>= 10.0.0'}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
libc: [musl]
'@parcel/watcher-win32-arm64@2.5.1': '@parcel/watcher-win32-arm64@2.5.1':
resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==} resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==}
@@ -388,6 +494,9 @@ packages:
'@rolldown/pluginutils@1.0.0-beta.53': '@rolldown/pluginutils@1.0.0-beta.53':
resolution: {integrity: sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ==} resolution: {integrity: sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ==}
'@rolldown/pluginutils@1.0.0-beta.59':
resolution: {integrity: sha512-aoh6LAJRyhtazs98ydgpNOYstxUlsOV1KJXcpf/0c0vFcUA8uyd/hwKRhqE/AAPNqAho9RliGsvitCoOzREoVA==}
'@rollup/rollup-android-arm-eabi@4.54.0': '@rollup/rollup-android-arm-eabi@4.54.0':
resolution: {integrity: sha512-OywsdRHrFvCdvsewAInDKCNyR3laPA2mc9bRYJ6LBp5IyvF3fvXbbNR0bSzHlZVFtn6E0xw2oZlyjg4rKCVcng==} resolution: {integrity: sha512-OywsdRHrFvCdvsewAInDKCNyR3laPA2mc9bRYJ6LBp5IyvF3fvXbbNR0bSzHlZVFtn6E0xw2oZlyjg4rKCVcng==}
cpu: [arm] cpu: [arm]
@@ -422,67 +531,56 @@ packages:
resolution: {integrity: sha512-EHMUcDwhtdRGlXZsGSIuXSYwD5kOT9NVnx9sqzYiwAc91wfYOE1g1djOEDseZJKKqtHAHGwnGPQu3kytmfaXLQ==} resolution: {integrity: sha512-EHMUcDwhtdRGlXZsGSIuXSYwD5kOT9NVnx9sqzYiwAc91wfYOE1g1djOEDseZJKKqtHAHGwnGPQu3kytmfaXLQ==}
cpu: [arm] cpu: [arm]
os: [linux] os: [linux]
libc: [glibc]
'@rollup/rollup-linux-arm-musleabihf@4.54.0': '@rollup/rollup-linux-arm-musleabihf@4.54.0':
resolution: {integrity: sha512-+pBrqEjaakN2ySv5RVrj/qLytYhPKEUwk+e3SFU5jTLHIcAtqh2rLrd/OkbNuHJpsBgxsD8ccJt5ga/SeG0JmA==} resolution: {integrity: sha512-+pBrqEjaakN2ySv5RVrj/qLytYhPKEUwk+e3SFU5jTLHIcAtqh2rLrd/OkbNuHJpsBgxsD8ccJt5ga/SeG0JmA==}
cpu: [arm] cpu: [arm]
os: [linux] os: [linux]
libc: [musl]
'@rollup/rollup-linux-arm64-gnu@4.54.0': '@rollup/rollup-linux-arm64-gnu@4.54.0':
resolution: {integrity: sha512-NSqc7rE9wuUaRBsBp5ckQ5CVz5aIRKCwsoa6WMF7G01sX3/qHUw/z4pv+D+ahL1EIKy6Enpcnz1RY8pf7bjwng==} resolution: {integrity: sha512-NSqc7rE9wuUaRBsBp5ckQ5CVz5aIRKCwsoa6WMF7G01sX3/qHUw/z4pv+D+ahL1EIKy6Enpcnz1RY8pf7bjwng==}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
libc: [glibc]
'@rollup/rollup-linux-arm64-musl@4.54.0': '@rollup/rollup-linux-arm64-musl@4.54.0':
resolution: {integrity: sha512-gr5vDbg3Bakga5kbdpqx81m2n9IX8M6gIMlQQIXiLTNeQW6CucvuInJ91EuCJ/JYvc+rcLLsDFcfAD1K7fMofg==} resolution: {integrity: sha512-gr5vDbg3Bakga5kbdpqx81m2n9IX8M6gIMlQQIXiLTNeQW6CucvuInJ91EuCJ/JYvc+rcLLsDFcfAD1K7fMofg==}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
libc: [musl]
'@rollup/rollup-linux-loong64-gnu@4.54.0': '@rollup/rollup-linux-loong64-gnu@4.54.0':
resolution: {integrity: sha512-gsrtB1NA3ZYj2vq0Rzkylo9ylCtW/PhpLEivlgWe0bpgtX5+9j9EZa0wtZiCjgu6zmSeZWyI/e2YRX1URozpIw==} resolution: {integrity: sha512-gsrtB1NA3ZYj2vq0Rzkylo9ylCtW/PhpLEivlgWe0bpgtX5+9j9EZa0wtZiCjgu6zmSeZWyI/e2YRX1URozpIw==}
cpu: [loong64] cpu: [loong64]
os: [linux] os: [linux]
libc: [glibc]
'@rollup/rollup-linux-ppc64-gnu@4.54.0': '@rollup/rollup-linux-ppc64-gnu@4.54.0':
resolution: {integrity: sha512-y3qNOfTBStmFNq+t4s7Tmc9hW2ENtPg8FeUD/VShI7rKxNW7O4fFeaYbMsd3tpFlIg1Q8IapFgy7Q9i2BqeBvA==} resolution: {integrity: sha512-y3qNOfTBStmFNq+t4s7Tmc9hW2ENtPg8FeUD/VShI7rKxNW7O4fFeaYbMsd3tpFlIg1Q8IapFgy7Q9i2BqeBvA==}
cpu: [ppc64] cpu: [ppc64]
os: [linux] os: [linux]
libc: [glibc]
'@rollup/rollup-linux-riscv64-gnu@4.54.0': '@rollup/rollup-linux-riscv64-gnu@4.54.0':
resolution: {integrity: sha512-89sepv7h2lIVPsFma8iwmccN7Yjjtgz0Rj/Ou6fEqg3HDhpCa+Et+YSufy27i6b0Wav69Qv4WBNl3Rs6pwhebQ==} resolution: {integrity: sha512-89sepv7h2lIVPsFma8iwmccN7Yjjtgz0Rj/Ou6fEqg3HDhpCa+Et+YSufy27i6b0Wav69Qv4WBNl3Rs6pwhebQ==}
cpu: [riscv64] cpu: [riscv64]
os: [linux] os: [linux]
libc: [glibc]
'@rollup/rollup-linux-riscv64-musl@4.54.0': '@rollup/rollup-linux-riscv64-musl@4.54.0':
resolution: {integrity: sha512-ZcU77ieh0M2Q8Ur7D5X7KvK+UxbXeDHwiOt/CPSBTI1fBmeDMivW0dPkdqkT4rOgDjrDDBUed9x4EgraIKoR2A==} resolution: {integrity: sha512-ZcU77ieh0M2Q8Ur7D5X7KvK+UxbXeDHwiOt/CPSBTI1fBmeDMivW0dPkdqkT4rOgDjrDDBUed9x4EgraIKoR2A==}
cpu: [riscv64] cpu: [riscv64]
os: [linux] os: [linux]
libc: [musl]
'@rollup/rollup-linux-s390x-gnu@4.54.0': '@rollup/rollup-linux-s390x-gnu@4.54.0':
resolution: {integrity: sha512-2AdWy5RdDF5+4YfG/YesGDDtbyJlC9LHmL6rZw6FurBJ5n4vFGupsOBGfwMRjBYH7qRQowT8D/U4LoSvVwOhSQ==} resolution: {integrity: sha512-2AdWy5RdDF5+4YfG/YesGDDtbyJlC9LHmL6rZw6FurBJ5n4vFGupsOBGfwMRjBYH7qRQowT8D/U4LoSvVwOhSQ==}
cpu: [s390x] cpu: [s390x]
os: [linux] os: [linux]
libc: [glibc]
'@rollup/rollup-linux-x64-gnu@4.54.0': '@rollup/rollup-linux-x64-gnu@4.54.0':
resolution: {integrity: sha512-WGt5J8Ij/rvyqpFexxk3ffKqqbLf9AqrTBbWDk7ApGUzaIs6V+s2s84kAxklFwmMF/vBNGrVdYgbblCOFFezMQ==} resolution: {integrity: sha512-WGt5J8Ij/rvyqpFexxk3ffKqqbLf9AqrTBbWDk7ApGUzaIs6V+s2s84kAxklFwmMF/vBNGrVdYgbblCOFFezMQ==}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
libc: [glibc]
'@rollup/rollup-linux-x64-musl@4.54.0': '@rollup/rollup-linux-x64-musl@4.54.0':
resolution: {integrity: sha512-JzQmb38ATzHjxlPHuTH6tE7ojnMKM2kYNzt44LO/jJi8BpceEC8QuXYA908n8r3CNuG/B3BV8VR3Hi1rYtmPiw==} resolution: {integrity: sha512-JzQmb38ATzHjxlPHuTH6tE7ojnMKM2kYNzt44LO/jJi8BpceEC8QuXYA908n8r3CNuG/B3BV8VR3Hi1rYtmPiw==}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
libc: [musl]
'@rollup/rollup-openharmony-arm64@4.54.0': '@rollup/rollup-openharmony-arm64@4.54.0':
resolution: {integrity: sha512-huT3fd0iC7jigGh7n3q/+lfPcXxBi+om/Rs3yiFxjvSxbSB6aohDFXbWvlspaqjeOh+hx7DDHS+5Es5qRkWkZg==} resolution: {integrity: sha512-huT3fd0iC7jigGh7n3q/+lfPcXxBi+om/Rs3yiFxjvSxbSB6aohDFXbWvlspaqjeOh+hx7DDHS+5Es5qRkWkZg==}
@@ -527,6 +625,13 @@ packages:
'@types/web-bluetooth@0.0.20': '@types/web-bluetooth@0.0.20':
resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==} resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==}
'@vitejs/plugin-vue-jsx@5.1.3':
resolution: {integrity: sha512-I6Zr8cYVr5WHMW5gNOP09DNqW9rgO8RX73Wa6Czgq/0ndpTfJM4vfDChfOT1+3KtdrNqilNBtNlFwVeB02ZzGw==}
engines: {node: ^20.19.0 || >=22.12.0}
peerDependencies:
vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0
vue: ^3.0.0
'@vitejs/plugin-vue@6.0.3': '@vitejs/plugin-vue@6.0.3':
resolution: {integrity: sha512-TlGPkLFLVOY3T7fZrwdvKpjprR3s4fxRln0ORDo1VQ7HHyxJwTlrjKU3kpVWTlaAjIEuCTokmjkZnr8Tpc925w==} resolution: {integrity: sha512-TlGPkLFLVOY3T7fZrwdvKpjprR3s4fxRln0ORDo1VQ7HHyxJwTlrjKU3kpVWTlaAjIEuCTokmjkZnr8Tpc925w==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
@@ -548,6 +653,22 @@ packages:
peerDependencies: peerDependencies:
vue: ^3.3.0 vue: ^3.3.0
'@vue/babel-helper-vue-transform-on@2.0.1':
resolution: {integrity: sha512-uZ66EaFbnnZSYqYEyplWvn46GhZ1KuYSThdT68p+am7MgBNbQ3hphTL9L+xSIsWkdktwhPYLwPgVWqo96jDdRA==}
'@vue/babel-plugin-jsx@2.0.1':
resolution: {integrity: sha512-a8CaLQjD/s4PVdhrLD/zT574ZNPnZBOY+IhdtKWRB4HRZ0I2tXBi5ne7d9eCfaYwp5gU5+4KIyFTV1W1YL9xZA==}
peerDependencies:
'@babel/core': ^7.0.0-0
peerDependenciesMeta:
'@babel/core':
optional: true
'@vue/babel-plugin-resolve-type@2.0.1':
resolution: {integrity: sha512-ybwgIuRGRRBhOU37GImDoWQoz+TlSqap65qVI6iwg/J7FfLTLmMf97TS7xQH9I7Qtr/gp161kYVdhr1ZMraSYQ==}
peerDependencies:
'@babel/core': ^7.0.0-0
'@vue/compiler-core@3.5.26': '@vue/compiler-core@3.5.26':
resolution: {integrity: sha512-vXyI5GMfuoBCnv5ucIT7jhHKl55Y477yxP6fc4eUswjP8FG3FFVFd41eNDArR+Uk3QKn2Z85NavjaxLxOC19/w==} resolution: {integrity: sha512-vXyI5GMfuoBCnv5ucIT7jhHKl55Y477yxP6fc4eUswjP8FG3FFVFd41eNDArR+Uk3QKn2Z85NavjaxLxOC19/w==}
@@ -629,6 +750,10 @@ packages:
axios@1.13.2: axios@1.13.2:
resolution: {integrity: sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==} resolution: {integrity: sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==}
baseline-browser-mapping@2.9.14:
resolution: {integrity: sha512-B0xUquLkiGLgHhpPBqvl7GWegWBUNuujQ6kXd/r1U38ElPT6Ok8KZ8e+FpUGEc2ZoRQUzq/aUnaKFc/svWUGSg==}
hasBin: true
birpc@2.9.0: birpc@2.9.0:
resolution: {integrity: sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==} resolution: {integrity: sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==}
@@ -636,10 +761,18 @@ packages:
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
engines: {node: '>=8'} engines: {node: '>=8'}
browserslist@4.28.1:
resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==}
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
hasBin: true
call-bind-apply-helpers@1.0.2: call-bind-apply-helpers@1.0.2:
resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
caniuse-lite@1.0.30001764:
resolution: {integrity: sha512-9JGuzl2M+vPL+pz70gtMF9sHdMFbY9FJaQBi186cHKH3pSzDvzoUJUPV6fqiKIMyXbud9ZLg4F3Yza1vJ1+93g==}
chokidar@4.0.3: chokidar@4.0.3:
resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==}
engines: {node: '>= 14.16.0'} engines: {node: '>= 14.16.0'}
@@ -654,6 +787,9 @@ packages:
confbox@0.2.2: confbox@0.2.2:
resolution: {integrity: sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==} resolution: {integrity: sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==}
convert-source-map@2.0.0:
resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
copy-anything@4.0.5: copy-anything@4.0.5:
resolution: {integrity: sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==} resolution: {integrity: sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==}
engines: {node: '>=18'} engines: {node: '>=18'}
@@ -724,6 +860,9 @@ packages:
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
electron-to-chromium@1.5.267:
resolution: {integrity: sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==}
element-plus@2.13.0: element-plus@2.13.0:
resolution: {integrity: sha512-qjxS+SBChvqCl6lU6ShiliLMN6WqFHiXQENYbAY3GKNflG+FS3jqn8JmQq0CBZq4koFqsi95NT1M6SL4whZfrA==} resolution: {integrity: sha512-qjxS+SBChvqCl6lU6ShiliLMN6WqFHiXQENYbAY3GKNflG+FS3jqn8JmQq0CBZq4koFqsi95NT1M6SL4whZfrA==}
peerDependencies: peerDependencies:
@@ -754,6 +893,10 @@ packages:
engines: {node: '>=18'} engines: {node: '>=18'}
hasBin: true hasBin: true
escalade@3.2.0:
resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
engines: {node: '>=6'}
escape-string-regexp@5.0.0: escape-string-regexp@5.0.0:
resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==}
engines: {node: '>=12'} engines: {node: '>=12'}
@@ -801,6 +944,10 @@ packages:
function-bind@1.1.2: function-bind@1.1.2:
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
gensync@1.0.0-beta.2:
resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
engines: {node: '>=6.9.0'}
get-intrinsic@1.3.0: get-intrinsic@1.3.0:
resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
@@ -847,9 +994,22 @@ packages:
resolution: {integrity: sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw==} resolution: {integrity: sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw==}
engines: {node: '>=18'} engines: {node: '>=18'}
js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
js-tokens@9.0.1: js-tokens@9.0.1:
resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==}
jsesc@3.1.0:
resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==}
engines: {node: '>=6'}
hasBin: true
json5@2.2.3:
resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}
engines: {node: '>=6'}
hasBin: true
local-pkg@1.1.2: local-pkg@1.1.2:
resolution: {integrity: sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==} resolution: {integrity: sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==}
engines: {node: '>=14'} engines: {node: '>=14'}
@@ -867,6 +1027,9 @@ packages:
lodash@4.17.21: lodash@4.17.21:
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
lru-cache@5.1.1:
resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
magic-string@0.30.21: magic-string@0.30.21:
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
@@ -909,6 +1072,9 @@ packages:
node-addon-api@7.1.1: node-addon-api@7.1.1:
resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==}
node-releases@2.0.27:
resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==}
normalize-wheel-es@1.2.0: normalize-wheel-es@1.2.0:
resolution: {integrity: sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw==} resolution: {integrity: sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw==}
@@ -977,6 +1143,10 @@ packages:
scule@1.3.0: scule@1.3.0:
resolution: {integrity: sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==} resolution: {integrity: sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==}
semver@6.3.1:
resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
hasBin: true
source-map-js@1.2.1: source-map-js@1.2.1:
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
@@ -1051,6 +1221,12 @@ packages:
resolution: {integrity: sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==} resolution: {integrity: sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==}
engines: {node: '>=18.12.0'} engines: {node: '>=18.12.0'}
update-browserslist-db@1.2.3:
resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==}
hasBin: true
peerDependencies:
browserslist: '>= 4.21.0'
vite@7.3.0: vite@7.3.0:
resolution: {integrity: sha512-dZwN5L1VlUBewiP6H9s2+B3e3Jg96D0vzN+Ry73sOefebhYr9f94wwkMNN/9ouoU8pV1BqA1d1zGk8928cx0rg==} resolution: {integrity: sha512-dZwN5L1VlUBewiP6H9s2+B3e3Jg96D0vzN+Ry73sOefebhYr9f94wwkMNN/9ouoU8pV1BqA1d1zGk8928cx0rg==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
@@ -1133,21 +1309,187 @@ packages:
webpack-virtual-modules@0.6.2: webpack-virtual-modules@0.6.2:
resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==}
yallist@3.1.1:
resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
snapshots: snapshots:
'@babel/code-frame@7.28.6':
dependencies:
'@babel/helper-validator-identifier': 7.28.5
js-tokens: 4.0.0
picocolors: 1.1.1
'@babel/compat-data@7.28.6': {}
'@babel/core@7.28.6':
dependencies:
'@babel/code-frame': 7.28.6
'@babel/generator': 7.28.6
'@babel/helper-compilation-targets': 7.28.6
'@babel/helper-module-transforms': 7.28.6(@babel/core@7.28.6)
'@babel/helpers': 7.28.6
'@babel/parser': 7.28.6
'@babel/template': 7.28.6
'@babel/traverse': 7.28.6
'@babel/types': 7.28.6
'@jridgewell/remapping': 2.3.5
convert-source-map: 2.0.0
debug: 4.4.3
gensync: 1.0.0-beta.2
json5: 2.2.3
semver: 6.3.1
transitivePeerDependencies:
- supports-color
'@babel/generator@7.28.6':
dependencies:
'@babel/parser': 7.28.6
'@babel/types': 7.28.6
'@jridgewell/gen-mapping': 0.3.13
'@jridgewell/trace-mapping': 0.3.31
jsesc: 3.1.0
'@babel/helper-annotate-as-pure@7.27.3':
dependencies:
'@babel/types': 7.28.5
'@babel/helper-compilation-targets@7.28.6':
dependencies:
'@babel/compat-data': 7.28.6
'@babel/helper-validator-option': 7.27.1
browserslist: 4.28.1
lru-cache: 5.1.1
semver: 6.3.1
'@babel/helper-create-class-features-plugin@7.28.6(@babel/core@7.28.6)':
dependencies:
'@babel/core': 7.28.6
'@babel/helper-annotate-as-pure': 7.27.3
'@babel/helper-member-expression-to-functions': 7.28.5
'@babel/helper-optimise-call-expression': 7.27.1
'@babel/helper-replace-supers': 7.28.6(@babel/core@7.28.6)
'@babel/helper-skip-transparent-expression-wrappers': 7.27.1
'@babel/traverse': 7.28.6
semver: 6.3.1
transitivePeerDependencies:
- supports-color
'@babel/helper-globals@7.28.0': {}
'@babel/helper-member-expression-to-functions@7.28.5':
dependencies:
'@babel/traverse': 7.28.6
'@babel/types': 7.28.5
transitivePeerDependencies:
- supports-color
'@babel/helper-module-imports@7.28.6':
dependencies:
'@babel/traverse': 7.28.6
'@babel/types': 7.28.6
transitivePeerDependencies:
- supports-color
'@babel/helper-module-transforms@7.28.6(@babel/core@7.28.6)':
dependencies:
'@babel/core': 7.28.6
'@babel/helper-module-imports': 7.28.6
'@babel/helper-validator-identifier': 7.28.5
'@babel/traverse': 7.28.6
transitivePeerDependencies:
- supports-color
'@babel/helper-optimise-call-expression@7.27.1':
dependencies:
'@babel/types': 7.28.5
'@babel/helper-plugin-utils@7.28.6': {}
'@babel/helper-replace-supers@7.28.6(@babel/core@7.28.6)':
dependencies:
'@babel/core': 7.28.6
'@babel/helper-member-expression-to-functions': 7.28.5
'@babel/helper-optimise-call-expression': 7.27.1
'@babel/traverse': 7.28.6
transitivePeerDependencies:
- supports-color
'@babel/helper-skip-transparent-expression-wrappers@7.27.1':
dependencies:
'@babel/traverse': 7.28.6
'@babel/types': 7.28.5
transitivePeerDependencies:
- supports-color
'@babel/helper-string-parser@7.27.1': {} '@babel/helper-string-parser@7.27.1': {}
'@babel/helper-validator-identifier@7.28.5': {} '@babel/helper-validator-identifier@7.28.5': {}
'@babel/helper-validator-option@7.27.1': {}
'@babel/helpers@7.28.6':
dependencies:
'@babel/template': 7.28.6
'@babel/types': 7.28.6
'@babel/parser@7.28.5': '@babel/parser@7.28.5':
dependencies: dependencies:
'@babel/types': 7.28.5 '@babel/types': 7.28.5
'@babel/parser@7.28.6':
dependencies:
'@babel/types': 7.28.6
'@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.28.6)':
dependencies:
'@babel/core': 7.28.6
'@babel/helper-plugin-utils': 7.28.6
'@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.28.6)':
dependencies:
'@babel/core': 7.28.6
'@babel/helper-plugin-utils': 7.28.6
'@babel/plugin-transform-typescript@7.28.6(@babel/core@7.28.6)':
dependencies:
'@babel/core': 7.28.6
'@babel/helper-annotate-as-pure': 7.27.3
'@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.28.6)
'@babel/helper-plugin-utils': 7.28.6
'@babel/helper-skip-transparent-expression-wrappers': 7.27.1
'@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.28.6)
transitivePeerDependencies:
- supports-color
'@babel/template@7.28.6':
dependencies:
'@babel/code-frame': 7.28.6
'@babel/parser': 7.28.6
'@babel/types': 7.28.6
'@babel/traverse@7.28.6':
dependencies:
'@babel/code-frame': 7.28.6
'@babel/generator': 7.28.6
'@babel/helper-globals': 7.28.0
'@babel/parser': 7.28.6
'@babel/template': 7.28.6
'@babel/types': 7.28.6
debug: 4.4.3
transitivePeerDependencies:
- supports-color
'@babel/types@7.28.5': '@babel/types@7.28.5':
dependencies: dependencies:
'@babel/helper-string-parser': 7.27.1 '@babel/helper-string-parser': 7.27.1
'@babel/helper-validator-identifier': 7.28.5 '@babel/helper-validator-identifier': 7.28.5
'@babel/types@7.28.6':
dependencies:
'@babel/helper-string-parser': 7.27.1
'@babel/helper-validator-identifier': 7.28.5
'@ctrl/tinycolor@3.6.1': {} '@ctrl/tinycolor@3.6.1': {}
'@element-plus/icons-vue@2.3.2(vue@3.5.26(typescript@5.9.3))': '@element-plus/icons-vue@2.3.2(vue@3.5.26(typescript@5.9.3))':
@@ -1339,6 +1681,8 @@ snapshots:
'@rolldown/pluginutils@1.0.0-beta.53': {} '@rolldown/pluginutils@1.0.0-beta.53': {}
'@rolldown/pluginutils@1.0.0-beta.59': {}
'@rollup/rollup-android-arm-eabi@4.54.0': '@rollup/rollup-android-arm-eabi@4.54.0':
optional: true optional: true
@@ -1421,6 +1765,18 @@ snapshots:
'@types/web-bluetooth@0.0.20': {} '@types/web-bluetooth@0.0.20': {}
'@vitejs/plugin-vue-jsx@5.1.3(vite@7.3.0(@types/node@24.10.4)(sass@1.97.1))(vue@3.5.26(typescript@5.9.3))':
dependencies:
'@babel/core': 7.28.6
'@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.28.6)
'@babel/plugin-transform-typescript': 7.28.6(@babel/core@7.28.6)
'@rolldown/pluginutils': 1.0.0-beta.59
'@vue/babel-plugin-jsx': 2.0.1(@babel/core@7.28.6)
vite: 7.3.0(@types/node@24.10.4)(sass@1.97.1)
vue: 3.5.26(typescript@5.9.3)
transitivePeerDependencies:
- supports-color
'@vitejs/plugin-vue@6.0.3(vite@7.3.0(@types/node@24.10.4)(sass@1.97.1))(vue@3.5.26(typescript@5.9.3))': '@vitejs/plugin-vue@6.0.3(vite@7.3.0(@types/node@24.10.4)(sass@1.97.1))(vue@3.5.26(typescript@5.9.3))':
dependencies: dependencies:
'@rolldown/pluginutils': 1.0.0-beta.53 '@rolldown/pluginutils': 1.0.0-beta.53
@@ -1450,6 +1806,35 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- '@vue/composition-api' - '@vue/composition-api'
'@vue/babel-helper-vue-transform-on@2.0.1': {}
'@vue/babel-plugin-jsx@2.0.1(@babel/core@7.28.6)':
dependencies:
'@babel/helper-module-imports': 7.28.6
'@babel/helper-plugin-utils': 7.28.6
'@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.28.6)
'@babel/template': 7.28.6
'@babel/traverse': 7.28.6
'@babel/types': 7.28.5
'@vue/babel-helper-vue-transform-on': 2.0.1
'@vue/babel-plugin-resolve-type': 2.0.1(@babel/core@7.28.6)
'@vue/shared': 3.5.26
optionalDependencies:
'@babel/core': 7.28.6
transitivePeerDependencies:
- supports-color
'@vue/babel-plugin-resolve-type@2.0.1(@babel/core@7.28.6)':
dependencies:
'@babel/code-frame': 7.28.6
'@babel/core': 7.28.6
'@babel/helper-module-imports': 7.28.6
'@babel/helper-plugin-utils': 7.28.6
'@babel/parser': 7.28.5
'@vue/compiler-sfc': 3.5.26
transitivePeerDependencies:
- supports-color
'@vue/compiler-core@3.5.26': '@vue/compiler-core@3.5.26':
dependencies: dependencies:
'@babel/parser': 7.28.5 '@babel/parser': 7.28.5
@@ -1574,6 +1959,8 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- debug - debug
baseline-browser-mapping@2.9.14: {}
birpc@2.9.0: {} birpc@2.9.0: {}
braces@3.0.3: braces@3.0.3:
@@ -1581,11 +1968,21 @@ snapshots:
fill-range: 7.1.1 fill-range: 7.1.1
optional: true optional: true
browserslist@4.28.1:
dependencies:
baseline-browser-mapping: 2.9.14
caniuse-lite: 1.0.30001764
electron-to-chromium: 1.5.267
node-releases: 2.0.27
update-browserslist-db: 1.2.3(browserslist@4.28.1)
call-bind-apply-helpers@1.0.2: call-bind-apply-helpers@1.0.2:
dependencies: dependencies:
es-errors: 1.3.0 es-errors: 1.3.0
function-bind: 1.1.2 function-bind: 1.1.2
caniuse-lite@1.0.30001764: {}
chokidar@4.0.3: chokidar@4.0.3:
dependencies: dependencies:
readdirp: 4.1.2 readdirp: 4.1.2
@@ -1598,6 +1995,8 @@ snapshots:
confbox@0.2.2: {} confbox@0.2.2: {}
convert-source-map@2.0.0: {}
copy-anything@4.0.5: copy-anything@4.0.5:
dependencies: dependencies:
is-what: 5.5.0 is-what: 5.5.0
@@ -1657,6 +2056,8 @@ snapshots:
es-errors: 1.3.0 es-errors: 1.3.0
gopd: 1.2.0 gopd: 1.2.0
electron-to-chromium@1.5.267: {}
element-plus@2.13.0(vue@3.5.26(typescript@5.9.3)): element-plus@2.13.0(vue@3.5.26(typescript@5.9.3)):
dependencies: dependencies:
'@ctrl/tinycolor': 3.6.1 '@ctrl/tinycolor': 3.6.1
@@ -1723,6 +2124,8 @@ snapshots:
'@esbuild/win32-ia32': 0.27.2 '@esbuild/win32-ia32': 0.27.2
'@esbuild/win32-x64': 0.27.2 '@esbuild/win32-x64': 0.27.2
escalade@3.2.0: {}
escape-string-regexp@5.0.0: {} escape-string-regexp@5.0.0: {}
estree-walker@2.0.2: {} estree-walker@2.0.2: {}
@@ -1757,6 +2160,8 @@ snapshots:
function-bind@1.1.2: {} function-bind@1.1.2: {}
gensync@1.0.0-beta.2: {}
get-intrinsic@1.3.0: get-intrinsic@1.3.0:
dependencies: dependencies:
call-bind-apply-helpers: 1.0.2 call-bind-apply-helpers: 1.0.2
@@ -1804,8 +2209,14 @@ snapshots:
is-what@5.5.0: {} is-what@5.5.0: {}
js-tokens@4.0.0: {}
js-tokens@9.0.1: {} js-tokens@9.0.1: {}
jsesc@3.1.0: {}
json5@2.2.3: {}
local-pkg@1.1.2: local-pkg@1.1.2:
dependencies: dependencies:
mlly: 1.8.0 mlly: 1.8.0
@@ -1822,6 +2233,10 @@ snapshots:
lodash@4.17.21: {} lodash@4.17.21: {}
lru-cache@5.1.1:
dependencies:
yallist: 3.1.1
magic-string@0.30.21: magic-string@0.30.21:
dependencies: dependencies:
'@jridgewell/sourcemap-codec': 1.5.5 '@jridgewell/sourcemap-codec': 1.5.5
@@ -1860,6 +2275,8 @@ snapshots:
node-addon-api@7.1.1: node-addon-api@7.1.1:
optional: true optional: true
node-releases@2.0.27: {}
normalize-wheel-es@1.2.0: {} normalize-wheel-es@1.2.0: {}
path-browserify@1.0.1: {} path-browserify@1.0.1: {}
@@ -1946,6 +2363,8 @@ snapshots:
scule@1.3.0: {} scule@1.3.0: {}
semver@6.3.1: {}
source-map-js@1.2.1: {} source-map-js@1.2.1: {}
speakingurl@14.0.1: {} speakingurl@14.0.1: {}
@@ -2009,7 +2428,7 @@ snapshots:
pathe: 2.0.3 pathe: 2.0.3
picomatch: 4.0.3 picomatch: 4.0.3
unplugin-vue-components@30.0.0(@babel/parser@7.28.5)(vue@3.5.26(typescript@5.9.3)): unplugin-vue-components@30.0.0(@babel/parser@7.28.6)(vue@3.5.26(typescript@5.9.3)):
dependencies: dependencies:
chokidar: 4.0.3 chokidar: 4.0.3
debug: 4.4.3 debug: 4.4.3
@@ -2021,7 +2440,7 @@ snapshots:
unplugin-utils: 0.3.1 unplugin-utils: 0.3.1
vue: 3.5.26(typescript@5.9.3) vue: 3.5.26(typescript@5.9.3)
optionalDependencies: optionalDependencies:
'@babel/parser': 7.28.5 '@babel/parser': 7.28.6
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -2032,6 +2451,12 @@ snapshots:
picomatch: 4.0.3 picomatch: 4.0.3
webpack-virtual-modules: 0.6.2 webpack-virtual-modules: 0.6.2
update-browserslist-db@1.2.3(browserslist@4.28.1):
dependencies:
browserslist: 4.28.1
escalade: 3.2.0
picocolors: 1.1.1
vite@7.3.0(@types/node@24.10.4)(sass@1.97.1): vite@7.3.0(@types/node@24.10.4)(sass@1.97.1):
dependencies: dependencies:
esbuild: 0.27.2 esbuild: 0.27.2
@@ -2080,3 +2505,5 @@ snapshots:
typescript: 5.9.3 typescript: 5.9.3
webpack-virtual-modules@0.6.2: {} webpack-virtual-modules@0.6.2: {}
yallist@3.1.1: {}

View File

@@ -19,6 +19,16 @@ export const login = (data: { username: string; password: string }) => {
}); });
}; };
// 获取字典映射
export const getDictMap = (ids:string) => {
return request.get(`/auth/v1/dict/type/${ids}`);
};
// 获取二级菜单数据
export const getDictMapLevel = (key:string,parentId:string) => {
return request.get(`/auth/v1/dict/type/${key}/${parentId}`);
};
/**员工公用接口*/ /**员工公用接口*/

View File

@@ -50,12 +50,12 @@ export const batchSaveRole = (roleId: string,data: number[]) => {
// 保存角色权限 // 保存角色权限
export const saveRolePermission = (data: any) => { export const saveRolePermission = (data: any) => {
return request.post(`/auth/v1/backend/role/permission/save`, data); return request.post(`/auth/v1/backend/role/permissions/save`, data);
} }
// 查询角色权限 // 查询角色权限 (获取角色权限详情)
export const getRolePermission = (roleId: string) => { export const getRolePermission = (roleId: string) => {
return request.get(`/auth/v1/backend/role/${roleId}/permission`); return request.get(`/auth/v1/backend/role/${roleId}/permissions`);
} }
// 获取角色成员列表 // 获取角色成员列表

View File

@@ -0,0 +1,126 @@
<template>
<div ref="tableContainerRef" class="pro-table-v2-container">
<el-table-v2
ref="tableRef"
v-bind="$attrs"
:columns="adaptedColumns"
:data="data"
:width="tableSize.width"
:height="tableSize.height"
:fixed="true"
@rows-rendered="handleRowsRendered"
>
<template #overlay v-if="loading">
<div class="v2-loading-overlay">
<el-icon class="is-loading" :size="26"><Loading /></el-icon>
</div>
</template>
</el-table-v2>
<div class="pro-table-v2-footer">
<div class="footer-left">
<span>已加载 {{ data.length }} / {{ total }} </span>
</div>
<div class="footer-right">
<span v-if="loading">加载中...</span>
<span v-else-if="noMore">已加载全部</span>
</div>
</div>
</div>
</template>
<script setup lang="tsx">
import { ref, computed, onMounted, onUnmounted } from "vue";
import { debounce } from 'lodash-es';
import { ElTag, ElText } from 'element-plus';
import NameAvatar from "@/components/NameAvatar/index.vue";
import dayjs from 'dayjs';
const props = defineProps({
columns: { type: Array, required: true },
data: { type: Array, required: true },
total: { type: Number, default: 0 },
loading: { type: Boolean, default: false },
});
const emit = defineEmits(["load-more"]);
// --- 内置渲染逻辑工厂 ---
const builtInRenderers = {
// 1. 人员头像渲染器 (默认读取 row.name 和 row.avatar)
member: (scope: any, col: any) => (
<div style="display:flex; align-items:center; gap:8px;">
<NameAvatar
name={scope.rowData[col.prop]}
src={scope.rowData[col.avatarKey || 'avatar']}
size={28}
/>
<span>{scope.rowData[col.prop]}</span>
</div>
),
// 2. 状态标签渲染器 (支持自定义映射)
status: (scope: any, col: any) => {
const val = scope.rowData[col.prop];
const option = col.options?.find((opt: any) => opt.value === val) || { label: val, type: 'info' };
return <ElTag type={option.type} size="small">{option.label}</ElTag>;
},
// 3. 日期格式化
date: (scope: any, col: any) => {
const val = scope.rowData[col.prop];
return <span>{val ? dayjs(val).format(col.format || 'YYYY-MM-DD HH:mm') : '-'}</span>;
},
// 4. 金额格式化
money: (scope: any, col: any) => {
const val = scope.rowData[col.prop];
return <ElText type="warning">¥ {Number(val || 0).toLocaleString()}</ElText>;
}
};
const adaptedColumns = computed(() => {
return props.columns.map((col: any) => ({
key: col.prop,
dataKey: col.prop,
title: col.label,
width: col.width || 150,
fixed: col.fixed,
align: col.align || 'left',
cellRenderer: (scope: any) => {
// 优先级 1: 用户自定义了 render 函数
if (typeof col.render === 'function') return col.render(scope);
// 优先级 2: 使用内置的 valueType 渲染器
if (col.valueType && builtInRenderers[col.valueType]) {
return builtInRenderers[col.valueType](scope, col);
}
// 优先级 3: 默认展示
return scope.rowData[col.prop] ?? '-';
},
}));
});
// --- 容器与滚动逻辑 (保持之前的一致) ---
const tableContainerRef = ref(null);
const tableSize = ref({ width: 0, height: 400 });
const noMore = computed(() => props.data.length >= props.total && props.total > 0);
const updateSize = () => {
if (tableContainerRef.value) {
const rect = tableContainerRef.value.getBoundingClientRect();
tableSize.value.width = rect.width;
tableSize.value.height = window.innerHeight - rect.top - 45;
}
};
const handleResize = debounce(updateSize, 200);
const handleRowsRendered = ({ endRowIndex }: any) => {
if (endRowIndex >= props.data.length - 5 && !props.loading && !noMore.value) {
emit("load-more");
}
};
onMounted(() => { updateSize(); window.addEventListener('resize', handleResize); });
onUnmounted(() => { window.removeEventListener('resize', handleResize); });
</script>

View File

@@ -20,7 +20,7 @@
<template #title>{{ row.meta.title }}</template> <template #title>{{ row.meta.title }}</template>
</el-menu-item> </el-menu-item>
</el-sub-menu> </el-sub-menu>
<el-menu-item v-else :index="item.path"> <el-menu-item v-else :index="getFirstChildPath(item)">
<el-icon v-if="item.meta?.icon"><component :is="item.meta.icon" /></el-icon> <el-icon v-if="item.meta?.icon"><component :is="item.meta.icon" /></el-icon>
<template #title>{{ item.meta.title }}</template> <template #title>{{ item.meta.title }}</template>
</el-menu-item> </el-menu-item>
@@ -68,6 +68,18 @@ const resolvePath = (parentPath: string, childPath: string) => {
// 4. 返回拼接后的路径 // 4. 返回拼接后的路径
return `${parent}/${child}`; return `${parent}/${child}`;
}; };
/**
* 获取菜单项的跳转路径
* 如果是顶级菜单且有子项,点击应跳转到第一个子项
*/
const getFirstChildPath = (item: any) => {
// 如果是顶级菜单且有子菜单
if (item.children && item.children.length > 0) {
return resolvePath(item.path, item.children[0].path);
}
// 如果没有子菜单,直接返回 item.path但要确保它是以 / 开头
return item.path.startsWith('/') ? item.path : `/${item.path}`;
};
// 处理菜单选中事件 // 处理菜单选中事件
const handleMenuSelect = (index: string) => { const handleMenuSelect = (index: string) => {

View File

@@ -1,37 +0,0 @@
// 后台 - 权限管理模块-权限内容信息
// 权限状态映射
const roleDict = {
1: '启用',
0: '禁用'
}
// 权限状态颜色
const roleDictColor = {
1:'#66E5BE',
0:'#90A1B9'
}
// 创建角色类型字典
const roleTypeOptions = [
{ label: '实例角色', value: 'INSTANCE' },
{ label: '默认角色', value: 'DEFAULT' },
{ label: '系统角色', value: 'SYSTEM' }
]
// 设置权限转换为目标格式
const statusOptions = Object.keys(roleDict).map((key) => {
return {
label: roleDict[key],
value: Number(key)
}
})
export default {
roleDict,
roleDictColor,
statusOptions,
roleTypeOptions
}

View File

@@ -1,29 +1,13 @@
// 后台 - 字典管理模块-字典内容信息 // 后台 - 字典管理模块-字典内容信息
// 字典状态映射
const statusDict = {
1: '正常',
0: '禁用'
}
// 字典状态颜色 // 字典状态颜色
const statusDictColor = { const statusDictColor = {
1:'#66E5BE', 1:'#66E5BE',
0:'#90A1B9' 0:'#90A1B9'
} }
// 设置字典转换为目标格式
const statusOptions = Object.keys(statusDict).map((key) => {
return {
label: statusDict[key],
value: Number(key)
}
})
export default { export default {
statusDict,
statusDictColor, statusDictColor,
statusOptions
} }

View File

@@ -9,6 +9,5 @@ Object.entries(modules).forEach(([path, module]: [string, any]) => {
// 2. 统一导出 // 2. 统一导出
export const { export const {
DictManage, DictManage,
PermissionManage
} = components; } = components;
export default components; export default components;

79
src/hooks/useDictData.ts Normal file
View File

@@ -0,0 +1,79 @@
import { ref, reactive, onMounted } from 'vue';
import { getDictMap,getDictMapLevel } from '@/api';
// 全局静态缓存,跨组件共享
const dictCache = reactive({});
const pendingPromises = new Map();
export function useDict(codes) {
const dicts = ref({});
const loading = ref(false);
const fetchDicts = async () => {
if (!codes) return;
const codeArray = codes.split(',').map(s => s.trim());
const result = {};
const needFetch = [];
// 1. 区分哪些在缓存,哪些需要查
codeArray.forEach(code => {
if (dictCache[code]) {
result[code] = dictCache[code];
} else {
needFetch.push(code);
}
});
if (needFetch.length === 0) {
dicts.value = result;
return;
}
// 2. 处理并发合并
const fetchKey = needFetch.sort().join(',');
if (!pendingPromises.has(fetchKey)) {
const p = getDictMap(codes).then(res => {
const data = res || [];
Object.assign(dictCache, data);
pendingPromises.delete(fetchKey);
return data;
});
pendingPromises.set(fetchKey, p);
}
loading.value = true;
try {
const remoteData = await pendingPromises.get(fetchKey);
dicts.value = { ...result, ...remoteData };
} finally {
loading.value = false;
}
};
const fetchLevel = async (code, parentId) => {
if (!code || parentId === undefined) return [];
// 构造层级缓存 Key例如 "GENDER_1"
const cacheKey = `${code}_${parentId}`;
if (dictCache[cacheKey]) {
return dictCache[cacheKey];
}
loading.value = true;
try {
// 假设 getDictMapLevel 接受 code 和 parentId
const res = await getDictMapLevel(code, parentId);
const data = res || [];
// 写入全局缓存
dictCache[cacheKey] = data;
return data;
} finally {
loading.value = false;
}
};
onMounted(fetchDicts);
return { dicts, loading,refresh: fetchDicts,fetchLevel };
}

View File

@@ -302,36 +302,26 @@ export const mockBackendMenuData = [
"name": "字典管理", "name": "字典管理",
"code": "dict", "code": "dict",
"icon": "OfficeBuilding", "icon": "OfficeBuilding",
"metadata": null,
"children": null
}, },
{ {
"name": "组织管理", "name": "组织管理",
"code": "origanization", "code": "origanization",
"icon": "OfficeBuilding", "icon": "OfficeBuilding",
"metadata": null,
"children": null
}, },
{ {
"name": "人员管理", "name": "人员管理",
"code": "personnel", "code": "personnel",
"icon": "OfficeBuilding", "icon": "OfficeBuilding",
"metadata": null,
"children": null
}, },
{ {
"name": "权限管理", "name": "权限管理",
"code": "permission", "code": "permission",
"icon": "OfficeBuilding", "icon": "OfficeBuilding",
"metadata": null,
"children": null
}, },
{ {
"name": "流程管理", "name": "流程管理",
"code": "flow", "code": "flow",
"icon": "OfficeBuilding", "icon": "OfficeBuilding",
"metadata": null,
"children": null
} }
] ]

View File

@@ -35,7 +35,7 @@
@menu-select="handleTopMenuSelect" @menu-select="handleTopMenuSelect"
/> />
<!-- 右侧用户的内容 --> <!-- 右侧用户的内容 -->
<rightMenuGroup @on-stage-manage="onStageManage" /> <rightMenuGroup @on-stage-manage="(path)=>handleTopMenuSelect(path)" />
</el-header> </el-header>
<el-main class="mj-main-backend-content"> <el-main class="mj-main-backend-content">
<router-view /> <router-view />
@@ -55,6 +55,7 @@ defineOptions({
const userStore = useUserStore(); const userStore = useUserStore();
const router = useRouter(); const router = useRouter();
const route = useRoute();
// 响应式断点(小屏阈值,小于此值视为小屏) // 响应式断点(小屏阈值,小于此值视为小屏)
const BREAKPOINT = 1024; const BREAKPOINT = 1024;
@@ -104,10 +105,7 @@ const backTitle = computed(()=>{
return menuList.value.find(itv=>itv.name === 'stage')?.meta?.title || '-'; return menuList.value.find(itv=>itv.name === 'stage')?.meta?.title || '-';
}) })
// 后台管理点击获取列表
const onStageManage = () =>{
selectedTopMenu.value = '/stage';
}
const topTitle = computed(() => { const topTitle = computed(() => {
return ( return (
@@ -165,6 +163,18 @@ const sideMenuList = computed(() => {
// 处理顶部菜单选中事件 // 处理顶部菜单选中事件
const handleTopMenuSelect = (menuPath: string) => { const handleTopMenuSelect = (menuPath: string) => {
selectedTopMenu.value = menuPath; selectedTopMenu.value = menuPath;
const currentModule = menuList.value.find(item => item.path === menuPath);
if (currentModule && currentModule.children && currentModule.children.length > 0) {
const firstChild = currentModule.children[0];
const targetPath = firstChild.path.startsWith("/")
? firstChild.path
: `${currentModule.path}/${firstChild.path}`;
router.push(targetPath);
selectedActiveMenu.value = targetPath;
} else {
router.push(menuPath);
}
}; };
// 左侧菜单选中事件 // 左侧菜单选中事件
@@ -172,23 +182,37 @@ const handleSideMenuSelect = (menuPath: string) => {
selectedActiveMenu.value = menuPath; selectedActiveMenu.value = menuPath;
}; };
// 高亮当前激活的菜单
const activeMenuByUrl = () => {
// 1. 获取当前路由路径,例如 "/stage/dict" 或 "/business/customer"
const currentPath = route.path;
// 2. 尝试从 topLevelMenuList 中直接找匹配项
let matchedMenu = topLevelMenuList.value.find(menu =>
currentPath.startsWith(menu.path)
);
// 3. 如果没找到,且路径以 /stage 开头 那就是后台管理模块
if (!matchedMenu && currentPath.startsWith('/stage')) {
selectedTopMenu.value = '/stage';
}else{
// 4. 赋值选中的菜单
if (matchedMenu) {
selectedTopMenu.value = matchedMenu.path;
} else if (topLevelMenuList.value.length > 0) {
selectedTopMenu.value = topLevelMenuList.value[0].path;
}
}
};
watch(() => route.path, () => {
activeMenuByUrl();
}, { immediate: true });
// 初始化:默认选中第一个菜单 // 初始化:默认选中第一个菜单
onMounted(() => { onMounted(() => {
const currentRoutePath = router.currentRoute.value.path; activeMenuByUrl();
const matchedTopMenu = topLevelMenuList.value.find(menu =>
currentRoutePath.startsWith(`${menu.path}/`) || currentRoutePath === menu.path
);
if (matchedTopMenu && matchedTopMenu.path) {
selectedTopMenu.value = matchedTopMenu.path;
} else if (topLevelMenuList.value.length > 0) {
// 否则默认选中第一个菜单
const firstMenu = topLevelMenuList.value[0];
if (firstMenu && firstMenu.path) {
selectedTopMenu.value = firstMenu.path;
}
}
// 监听窗口大小变化 // 监听窗口大小变化
window.addEventListener("resize", handleResize); window.addEventListener("resize", handleResize);

View File

@@ -80,7 +80,7 @@ const handleCommand = (command: string) => {
}; };
const onStageManage = () => { const onStageManage = () => {
emits("on-stage-manage"); emits("on-stage-manage",'/stage');
}; };
// 获取当前的用户的数据信息 // 获取当前的用户的数据信息

View File

@@ -110,19 +110,9 @@
}" }"
@click="handleDictStatus(row)" @click="handleDictStatus(row)"
> >
{{ DictManage.statusDict[row.status] }} {{ dicts.permission_list_enable_disable.find(item=>item.value == row.status)?.label }}
</div> </div>
</template> </template>
<!-- <template #actions="{ row }">
<el-button link type="primary" v-if="!hasChild" @click="handleAddNext(row)"
>添加二级字段</el-button>
<el-button link type="primary" @click="handleEdit(row)"
>编辑</el-button
>
<el-button link type="danger" @click="handleDelete(row)"
>删除</el-button
>
</template> -->
</CommonTable> </CommonTable>
<!-- 新增字段 --> <!-- 新增字段 -->
<dictFieldLevelManage <dictFieldLevelManage
@@ -147,6 +137,8 @@ import CommonTable from "@/components/proTable/index.vue";
import dayjs from "dayjs"; import dayjs from "dayjs";
import dictFieldLevelManage from "./dictFieldLevelManage.vue"; import dictFieldLevelManage from "./dictFieldLevelManage.vue";
import { DictManage } from "@/dict"; import { DictManage } from "@/dict";
import { useDict } from '@/hooks/useDictData';
const { dicts,refresh } = useDict('permission_list_enable_disable');
import { import {
getDictTypeValue, getDictTypeValue,
deleteDictTypeValue, deleteDictTypeValue,

View File

@@ -18,10 +18,17 @@
label-width="120px" label-width="120px"
> >
<el-form-item label="字段名称:" prop="label"> <el-form-item label="字段名称:" prop="label">
<el-input placeholder="请输入字典名称" v-model="form.label"></el-input> <el-input
placeholder="请输入字典名称"
v-model="form.label"
></el-input>
</el-form-item> </el-form-item>
<el-form-item label="字典值:" prop="value"> <el-form-item label="字典值:" prop="value">
<el-input placeholder="请输入字典值" v-model="form.value" :disabled="form.id ? true : false"></el-input> <el-input
placeholder="请输入字典值"
v-model="form.value"
:disabled="form.id ? true : false"
></el-input>
</el-form-item> </el-form-item>
<el-form-item prop="sort"> <el-form-item prop="sort">
<template #label> <template #label>
@@ -34,12 +41,21 @@
</div> </div>
</template> </template>
<!-- 换成排序的输入框 --> <!-- 换成排序的输入框 -->
<el-input-number placeholder="请输入排序" v-model="form.sort" :min="0" controls-position="right"></el-input-number> <el-input-number
placeholder="请输入排序"
v-model="form.sort"
:min="0"
controls-position="right"
></el-input-number>
</el-form-item> </el-form-item>
<el-form-item label="状态:" prop="status"> <el-form-item label="状态:" prop="status">
<el-radio-group v-model="form.status"> <el-radio-group v-model="form.status">
<el-radio :value="1">启用</el-radio> <el-radio
<el-radio :value="0">停用</el-radio> :value="item.value"
v-for="(item, index) in dicts.permission_list_enable_disable"
:key="item.value"
>{{ item.label }}</el-radio
>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item label="备注:" prop="remark"> <el-form-item label="备注:" prop="remark">
@@ -55,7 +71,12 @@
</el-form> </el-form>
<template #footer> <template #footer>
<el-button @click="onCancel">取消</el-button> <el-button @click="onCancel">取消</el-button>
<el-button @click="onConfirm(ruleFormRef)" type="primary" :loading="loading">确认</el-button> <el-button
@click="onConfirm(ruleFormRef)"
type="primary"
:loading="loading"
>确认</el-button
>
</template> </template>
</el-dialog> </el-dialog>
</div> </div>
@@ -64,6 +85,8 @@
import { reactive, ref, onMounted } from "vue"; import { reactive, ref, onMounted } from "vue";
import { ElMessage, type FormInstance, type FormRules } from "element-plus"; import { ElMessage, type FormInstance, type FormRules } from "element-plus";
import { saveDictTypeValue, updateDictTypeValue } from "@/api/stage/dict"; import { saveDictTypeValue, updateDictTypeValue } from "@/api/stage/dict";
import { useDict } from "@/hooks/useDictData";
const { dicts, refresh } = useDict("permission_list_enable_disable");
defineOptions({ name: "DictFieldLevelManage" }); defineOptions({ name: "DictFieldLevelManage" });
const loading = ref(false); const loading = ref(false);
const { const {
@@ -78,8 +101,6 @@ const {
title?: string; title?: string;
}>(); }>();
const emit = defineEmits<{ const emit = defineEmits<{
(e: "update:dialogVisible", value: boolean): void; (e: "update:dialogVisible", value: boolean): void;
(e: "confirm-success"): void; (e: "confirm-success"): void;
@@ -90,22 +111,26 @@ const form = reactive({
label: "", label: "",
value: "", value: "",
sort: 0, sort: 0,
status:1, status: '1',
remark:'' remark: "",
}); });
// 监听组件中传递的数据-然后进行复制操作 // 监听组件中传递的数据-然后进行复制操作
watch(()=>row,(newRow)=>{ watch(
() => row,
(newRow) => {
if (newRow && Object.keys(newRow).length > 0) { if (newRow && Object.keys(newRow).length > 0) {
Object.assign(form, newRow); Object.assign(form, newRow,{status:String(newRow.status)});
} }
},{deep:true}) },
{ deep: true }
);
const rules = reactive({ const rules = reactive({
label: [{ required: true, message: "请输入字段名称", trigger: "blur" }], label: [{ required: true, message: "请输入字段名称", trigger: "blur" }],
value: [{ required: true, message: "请输入字典值", trigger: "blur" }], value: [{ required: true, message: "请输入字典值", trigger: "blur" }],
sort: [{ required: true, message: "请输入排序", trigger: "blur" }], sort: [{ required: true, message: "请输入排序", trigger: "blur" }],
remark:[{ required: false, message: "请输入备注", trigger: "blur" }] remark: [{ required: false, message: "请输入备注", trigger: "blur" }],
}); });
// 确定 // 确定
@@ -114,15 +139,17 @@ const onConfirm = async (formEl: FormInstance | undefined) => {
await formEl.validate(async (valid, fields) => { await formEl.validate(async (valid, fields) => {
if (valid) { if (valid) {
loading.value = true; loading.value = true;
console.log("获取外部的数据信息:",form,parentId) console.log("获取外部的数据信息:", form, parentId);
// 如果是一级新增字段就是parentId为0 如果是添加二级字段就是parentId为父级的id // 如果是一级新增字段就是parentId为0 如果是添加二级字段就是parentId为父级的id
try { try {
const response = row.id ? await updateDictTypeValue(parentId,row.id,form) : await saveDictTypeValue(parentId,form); const response = row.id
ElMessage.success(row.id ? '修改成功' : '新增成功'); ? await updateDictTypeValue(parentId, row.id, form)
: await saveDictTypeValue(parentId, form);
ElMessage.success(row.id ? "修改成功" : "新增成功");
onCancel(); onCancel();
emit('confirm-success'); emit("confirm-success");
} catch (error) { } catch (error) {
console.log('error',error); console.log("error", error);
} finally { } finally {
loading.value = false; loading.value = false;
} }

View File

@@ -34,8 +34,12 @@
</el-form-item> </el-form-item>
<el-form-item label="状态:" prop="status"> <el-form-item label="状态:" prop="status">
<el-radio-group v-model="form.status"> <el-radio-group v-model="form.status">
<el-radio :value="1">启用</el-radio> <el-radio
<el-radio :value="0">停用</el-radio> :value="item.value"
v-for="(item, index) in dicts.permission_list_enable_disable"
:key="item.value"
>{{ item.label }}</el-radio
>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item label="备注:"> <el-form-item label="备注:">
@@ -60,6 +64,8 @@
import { reactive, ref, onMounted } from "vue"; import { reactive, ref, onMounted } from "vue";
import { ElMessage, type FormInstance, type FormRules } from "element-plus"; import { ElMessage, type FormInstance, type FormRules } from "element-plus";
import { addDictValue, updateDictValue } from "@/api/stage/dict"; import { addDictValue, updateDictValue } from "@/api/stage/dict";
import { useDict } from "@/hooks/useDictData";
const { dicts, refresh } = useDict("permission_list_enable_disable");
defineOptions({ name: "DictManage" }); defineOptions({ name: "DictManage" });
const loading = ref(false); const loading = ref(false);
const { const {
@@ -80,14 +86,14 @@ const ruleFormRef = ref<FormInstance>();
const form = reactive({ const form = reactive({
name: "", name: "",
key: "", key: "",
status: 1, status: '1',
remark: "", remark: "",
}); });
// 监听组件中传递的数据-然后进行复制操作 // 监听组件中传递的数据-然后进行复制操作
watch(()=>row,(newRow)=>{ watch(()=>row,(newRow)=>{
if (newRow && Object.keys(newRow).length > 0) { if (newRow && Object.keys(newRow).length > 0) {
Object.assign(form, newRow); Object.assign(form, newRow,{status:String(newRow.status)});
} }
},{deep:true}) },{deep:true})

View File

@@ -33,7 +33,7 @@
<el-option <el-option
:label="item.label" :label="item.label"
:value="item.value" :value="item.value"
v-for="(item, index) in DictManage.statusOptions" v-for="(item, index) in dicts.permission_list_enable_disable"
:key="index" :key="index"
/> />
</el-select> </el-select>
@@ -89,19 +89,9 @@
}" }"
@click="handleDictStatus(row)" @click="handleDictStatus(row)"
> >
{{ DictManage.statusDict[row.status] }} {{ dicts.permission_list_enable_disable.find(item=>item.value == row.status)?.label }}
</div> </div>
</template> </template>
<!-- <template #actions="{ row }">
<el-button link type="primary" @click="handleEdit(row)">编辑</el-button>
<el-button link type="primary" @click="handlefieldsConfig(row)"
>字段配置</el-button
>
<el-button link type="danger" @click="handleDelete(row)"
>删除</el-button
>
</template> -->
</CommonTable> </CommonTable>
<!-- 新增-编辑字典弹窗 --> <!-- 新增-编辑字典弹窗 -->
@@ -130,6 +120,9 @@ import { DictManage } from "@/dict";
import { formatIndex } from "@/utils/utils"; import { formatIndex } from "@/utils/utils";
import { ElMessage } from "element-plus"; import { ElMessage } from "element-plus";
import { useDict } from '@/hooks/useDictData';
const { dicts,refresh } = useDict('permission_list_enable_disable');
defineOptions({ name: "Dictionary" }); defineOptions({ name: "Dictionary" });
const fieldsConfigRef = ref(null); const fieldsConfigRef = ref(null);
const dictTableRef = ref(null); const dictTableRef = ref(null);

View File

@@ -28,7 +28,7 @@
<div class="full-width-radio"> <div class="full-width-radio">
<BaseSegmented <BaseSegmented
v-model="form.type" v-model="form.type"
:options="PermissionManage.roleTypeOptions" :options="dicts.permission_role_type"
/> />
</div> </div>
</el-form-item> </el-form-item>
@@ -117,7 +117,6 @@
<script lang="ts" setup> <script lang="ts" setup>
import BaseSegmented from "./baseSegmented.vue"; import BaseSegmented from "./baseSegmented.vue";
import { PermissionManage } from "@/dict";
import { Loading } from "@element-plus/icons-vue"; import { Loading } from "@element-plus/icons-vue";
import type { FormInstance, FormRules } from "element-plus"; import type { FormInstance, FormRules } from "element-plus";
import { import {
@@ -127,6 +126,8 @@ import {
} from "@/api/stage/permission/index.ts"; } from "@/api/stage/permission/index.ts";
import { getEnterprisePosition } from "@/api/stage/organization"; import { getEnterprisePosition } from "@/api/stage/organization";
import { useSelectLoadMore } from "@/hooks/useSelectLoadMore"; import { useSelectLoadMore } from "@/hooks/useSelectLoadMore";
import { useDict } from '@/hooks/useDictData';
const { dicts,refresh } = useDict('permission_role_type');
defineOptions({ name: "addRoles" }); defineOptions({ name: "addRoles" });
const dialogVisible = defineModel("visible", { type: Boolean, default: false }); const dialogVisible = defineModel("visible", { type: Boolean, default: false });
const props = defineProps({ const props = defineProps({
@@ -135,7 +136,6 @@ const props = defineProps({
default: "", default: "",
}, },
}); });
const { const {
options, options,
remoteLoading, remoteLoading,
@@ -219,6 +219,11 @@ const handleSubmit = (formEl: FormInstance | undefined) => {
} }
}); });
}; };
// 初始化刷新角色类型值
onMounted(() => {
refresh();
});
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -1,16 +1,14 @@
<template> <template>
<div class="permission-scroll-area"> <div class="permission-scroll-area">
<div v-for="group in permissions" :key="group.id" class="permission-group"> <div v-for="group in menuList" :key="group.id" class="permission-group">
<div class="group-header"> <div class="group-header">
<el-checkbox <el-checkbox
v-model="group.allSelected" v-model="group.selected"
:indeterminate="group.isIndeterminate" :indeterminate="group.isIndeterminate"
@change="(val) => handleGroupCheckAll(group, val)" @change="(val) => handleGroupCheckAll(group, val)"
> >
<span class="group-title">{{ group.name }}</span> <span class="group-title">{{ group.name }}</span>
<span class="group-count" <span class="group-count" v-if="group.children">({{ getCheckedCount(group) }}/{{ group.children.length }})</span>
>({{ getCheckedCount(group) }}/{{ group.children.length }})</span
>
</el-checkbox> </el-checkbox>
</div> </div>
@@ -18,23 +16,19 @@
<div v-for="row in group.children" :key="row.id" class="permission-row"> <div v-for="row in group.children" :key="row.id" class="permission-row">
<div class="row-label"> <div class="row-label">
<el-checkbox <el-checkbox
v-model="row.checked" v-model="row.selected"
:indeterminate="row.isIndeterminate"
@change="() => handleRowChange(group, row)" @change="() => handleRowChange(group, row)"
> >
{{ row.name }} {{ row.name }}
</el-checkbox> </el-checkbox>
</div> </div>
<div class="row-actions"> <div class="row-actions">
<el-checkbox-group <el-checkbox-group
v-model="row.actions" v-model="row.actions"
:disabled="!row.checked"
@change="() => handleActionChange(group, row)" @change="() => handleActionChange(group, row)"
> >
<el-checkbox value="add">新增</el-checkbox> <el-checkbox :value="check.id" v-for="(check,checkIndex) in row.operations" :class="check.code.search('delete') > -1 ? 'is-danger' : ''">{{ check.name }}</el-checkbox>
<el-checkbox value="delete" class="is-danger">删除</el-checkbox>
<el-checkbox value="import">导入</el-checkbox>
<el-checkbox value="export">导出</el-checkbox>
</el-checkbox-group> </el-checkbox-group>
</div> </div>
</div> </div>
@@ -43,123 +37,55 @@
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { reactive, ref, onMounted } from "vue";
defineOptions({name: "baseSegmentedMenu"}); defineOptions({name: "baseSegmentedMenu"});
// 模拟数据结构 const props = defineProps({
const permissions = reactive([ menuList: {
{ type: Array,
id: 1, default: () => [],
name: "项目管理",
allSelected: false,
isIndeterminate: true,
children: [
{
id: 11,
name: "需求管理",
checked: true,
actions: ["add", "delete", "import", "export"],
}, },
{ id: 12, name: "项目管理", checked: false, actions: [] }, });
{ id: 13, name: "任务管理", checked: false, actions: [] },
],
},
{
id: 2,
name: "招聘管理",
allSelected: false,
isIndeterminate: false,
children: [
{ id: 21, name: "简历管理", checked: false, actions: [] },
{ id: 22, name: "推送管理", checked: false, actions: [] },
],
},
{
id: 2,
name: "招聘管理",
allSelected: false,
isIndeterminate: false,
children: [
{ id: 21, name: "简历管理", checked: false, actions: [] },
{ id: 22, name: "推送管理", checked: false, actions: [] },
],
},
{
id: 2,
name: "招聘管理",
allSelected: false,
isIndeterminate: false,
children: [
{ id: 21, name: "简历管理", checked: false, actions: [] },
{ id: 22, name: "推送管理", checked: false, actions: [] },
],
},
{
id: 2,
name: "招聘管理",
allSelected: false,
isIndeterminate: false,
children: [
{ id: 21, name: "简历管理", checked: false, actions: [] },
{ id: 22, name: "推送管理", checked: false, actions: [] },
],
},
{
id: 2,
name: "招聘管理",
allSelected: false,
isIndeterminate: false,
children: [
{ id: 21, name: "简历管理", checked: false, actions: [] },
{ id: 22, name: "推送管理", checked: false, actions: [] },
],
},
{
id: 2,
name: "招聘管理",
allSelected: false,
isIndeterminate: false,
children: [
{ id: 21, name: "简历管理", checked: false, actions: [] },
{ id: 22, name: "推送管理", checked: false, actions: [] },
],
},
]);
// 获取已选中的子项数量 // 获取已选中的子项数量
const getCheckedCount = (group) => const getCheckedCount = (group) =>{
group.children.filter((item) => item.checked).length; return (group.children || []).filter((item) => item.selected).length;
}
// 处理一级全选 // 处理一级全选
const handleGroupCheckAll = (group, val) => { const handleGroupCheckAll = (group, val) => {
group.children.forEach((row) => { group.children.forEach((row) => {
row.checked = val; row.selected = val;
row.actions = val ? ["add", "delete", "import", "export"] : []; row.actions = val ? row.operations.map((item) => item.id) : [];
}); });
group.isIndeterminate = false; group.isIndeterminate = false;
}; };
// 处理二级勾选 // 处理二级勾选
const handleRowChange = (group, row) => { const handleRowChange = (group, row) => {
if (!row.checked) row.actions = []; row.actions = row.selected ? row.operations.map((item) => item.id) : [];
updateGroupStatus(group); updateGroupStatus(group);
}; };
// 处理三级按钮勾选 // 处理三级按钮勾选
const handleActionChange = (group, row) => { const handleActionChange = (group, row) => {
if (row.actions.length > 0) row.checked = true; if (row.actions.length > 0) row.selected = true;
const allActions = row.operations && row.operations.length;
const checkedActionsCount = row.actions ? row.actions.length : 0;
row.isIndeterminate = checkedActionsCount > 0 && checkedActionsCount < allActions;
row.selected = checkedActionsCount > 0 && checkedActionsCount === allActions;
updateGroupStatus(group); updateGroupStatus(group);
}; };
// 更新父级的半选/全选状态 // 更新父级的半选/全选状态
const updateGroupStatus = (group) => { const updateGroupStatus = (group) => {
const checkedCount = getCheckedCount(group); const children = group.children || [];
group.allSelected = checkedCount === group.children.length; const total = children.length;
group.isIndeterminate = const fullyCheckedCount = children.filter(c => c.selected && !c.isIndeterminate).length;
checkedCount > 0 && checkedCount < group.children.length; const anyCheckedCount = children.filter(c => c.selected || c.isIndeterminate).length;
group.selected = total > 0 && fullyCheckedCount === total;
group.isIndeterminate = !group.selected && anyCheckedCount > 0;
}; };
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@use './baseSegmentedPermission.scss' as *; @use './baseSegmentedPermission.scss' as *;
</style> </style>

View File

@@ -20,8 +20,6 @@
</template> </template>
<script setup> <script setup>
import { inject } from "vue";
import { computed } from "vue";
import { useFormItem } from "element-plus"; import { useFormItem } from "element-plus";
const props = defineProps({ const props = defineProps({
modelValue: [String, Number], modelValue: [String, Number],
@@ -31,6 +29,11 @@ const props = defineProps({
}, },
}); });
watch(() => props.options, (val) => {
// 1. 获取父组件的值
console.log("父组件的值111", val);
},{deep:true});
const emit = defineEmits(["update:modelValue", "change"]); const emit = defineEmits(["update:modelValue", "change"]);
// 生成唯一ID防止页面存在多个组件时 name 冲突 // 生成唯一ID防止页面存在多个组件时 name 冲突
@@ -42,7 +45,7 @@ const handleChange = (val) => {
emit("update:modelValue", val); emit("update:modelValue", val);
emit("change", val); emit("change", val);
// 3. 关键:通知 el-form-item 进行校验 // 通知 el-form-item 进行校验
if (formItem) { if (formItem) {
formItem.validate("change").catch(() => {}); formItem.validate("change").catch(() => {});
} }

View File

@@ -5,7 +5,7 @@
v-for="mod in modules" v-for="mod in modules"
:key="mod.id" :key="mod.id"
class="module-card" class="module-card"
:class="{ 'is-active': modelValue === mod.id }" :class="{ 'is-active': activeModules === mod.id }"
@click="handleModuleChange(mod.id)" @click="handleModuleChange(mod.id)"
> >
{{ mod.name }} {{ mod.name }}
@@ -13,23 +13,24 @@
</div> </div>
<div class="field-group-list"> <div class="field-group-list">
<template v-if="fieldGroupsChildren.length">
<div <div
v-for="(group, index) in fieldGroups" v-for="(group, index) in fieldGroupsChildren"
:key="group.groupId" :key="group.id"
class="group-container" class="group-container"
:class="{ 'is-collapsed': group.collapsed }" :class="{ 'is-collapsed': collapsedIds.has(group.id) }"
> >
<div class="group-header" :class="{ 'is-collapsed': group.collapsed }"> <div class="group-header" :class="{ 'is-collapsed': collapsedIds.has(group.id) }">
<div class="header-left"> <div class="header-left">
<el-icon><List /></el-icon> <el-icon><List /></el-icon>
<span class="group-title">{{ group.groupName }}</span> <span class="group-title">{{ group.name }}</span>
</div> </div>
<div class="header-right"> <div class="header-right">
<span class="quick-set-label">快速设置</span> <span class="quick-set-label">快速设置</span>
<div class="quick-actions"> <div class="quick-actions">
<span <span
v-for="opt in quickOptions" v-for="opt in dicts.permission_setting_status"
:key="opt.value" :key="opt.value"
class="quick-btn" class="quick-btn"
:class="{ 'is-disabled': isProcessing }" :class="{ 'is-disabled': isProcessing }"
@@ -38,7 +39,7 @@
{{ opt.label }} {{ opt.label }}
</span> </span>
</div> </div>
<el-icon class="collapse-icon" @click.stop="toggleGroup(index)" <el-icon class="collapse-icon" @click.stop="toggleGroup(group)"
><ArrowDown ><ArrowDown
/></el-icon> /></el-icon>
</div> </div>
@@ -56,15 +57,22 @@
</div> </div>
<div class="field-ctrl"> <div class="field-ctrl">
<el-select v-model="field.permission"> <el-select v-model="field.permission">
<el-option label="可查看" value="read" /> <el-option
<el-option label="可编辑" value="edit" /> :label="dict.label"
<el-option label="不可查看" value="none" /> :value="dict.value"
v-for="(
dict, dicIndex
) in dicts.permission_setting_status"
:key="dict.value"
/>
</el-select> </el-select>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</template>
<el-empty description="暂无数据~" v-else/>
</div> </div>
</div> </div>
</template> </template>
@@ -74,26 +82,61 @@ import { ref, computed } from "vue";
import { List, Document, ArrowDown } from "@element-plus/icons-vue"; import { List, Document, ArrowDown } from "@element-plus/icons-vue";
const props = defineProps({ const props = defineProps({
// 模块列表 dicts:{
modules: { type: Array, default: () => [] }, type:Object,
// 初始选中的模块ID default:()=>({})
modelValue: [String, Number], },
fieldGroups: { fieldGroupsList: {
type: Array, type: Array,
default: () => [], default: () => [],
}, }
}); });
const emit = defineEmits(["update:modelValue", "update:fieldGroups", "change"]); const emit = defineEmits(["update:fieldGroupsList"]);
const isProcessing = ref(false); const isProcessing = ref(false);
const processingGroupId = ref(null); const processingGroupId = ref(null);
const currentActiveId = ref(null);
const collapsedIds = ref(new Set()); //可折叠的集合
// 渲染顶部的数据
const modules = computed(() => {
return props.fieldGroupsList.map((group) => {
return {
id: group.id,
name: group.name,
};
});
});
// 快速设置选项 // 动态渲染activeModules的值
const quickOptions = [ const activeModules = computed(() => currentActiveId.value);
{ label: "可查看", value: "read" },
{ label: "可编辑", value: "edit" }, // 动态匹配对应的下级数据
{ label: "不可查看", value: "none" }, const fieldGroupsChildren = computed({
]; get: () => {
if (!currentActiveId.value) return [];
return (
props.fieldGroupsList.find((group) => group.id === currentActiveId.value)
?.fieldGroups || []
);
},
set: () => {},
});
// 监听值的变化
watch(
() => props.fieldGroupsList,
(newList) => {
if (newList.length > 0) {
const exists = newList.find((item) => item.id === currentActiveId.value);
if (!exists) {
currentActiveId.value = newList[0].id;
}
} else {
currentActiveId.value = null;
}
},
{ immediate: true, deep: true }
);
const batchSetPermissionChunked = (group, type) => { const batchSetPermissionChunked = (group, type) => {
if (isProcessing.value) return; if (isProcessing.value) return;
@@ -105,6 +148,8 @@ const batchSetPermissionChunked = (group, type) => {
isProcessing.value = true; isProcessing.value = true;
processingGroupId.value = group.groupId; processingGroupId.value = group.groupId;
// 同步更新permission的数据
group.permission = type;
const runChunk = () => { const runChunk = () => {
const nextLimit = Math.min(currentIndex + chunkSize, total); const nextLimit = Math.min(currentIndex + chunkSize, total);
@@ -120,31 +165,27 @@ const batchSetPermissionChunked = (group, type) => {
} else { } else {
isProcessing.value = false; isProcessing.value = false;
processingGroupId.value = null; processingGroupId.value = null;
emit("update:fieldGroups", [...props.fieldGroups]); emit("update:fieldGroupsList", [...props.fieldGroupsList]);
} }
}; };
runChunk(); runChunk();
}; };
// 切换折叠逻辑 // 切换折叠面板
const toggleGroup = (index) => { const toggleGroup = (group) => {
console.log(""); if (collapsedIds.value.has(group.id)) {
props.fieldGroups[index].collapsed = !props.fieldGroups[index].collapsed; collapsedIds.value.delete(group.id);
} else {
collapsedIds.value.add(group.id);
}
}; };
// 切换顶部权限的模块
const handleModuleChange = (id) => { const handleModuleChange = (id) => {
emit("update:modelValue", id); currentActiveId.value = id;
emit("change", id);
}; };
// 批量设置权限逻辑
const batchSetPermission = (group, type) => {
group.fields.forEach((field) => {
field.permission = type;
});
emit("update:fieldGroups", [...props.fieldGroups]);
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -41,11 +41,11 @@
<div <div
class="mj-status-dot" class="mj-status-dot"
:style="{ :style="{
'--data-status-color': PermissionManage.roleDictColor[row.status], '--data-status-color': DictManage.statusDictColor[row.status],
}" }"
@click="handleDictStatus(row)" @click="handleDictStatus(row)"
> >
{{ PermissionManage.roleDict[row.status] }} {{ dicts.permission_list_enable_disable.find(item=>item.value == row.status)?.label }}
</div> </div>
</template> </template>
@@ -78,11 +78,11 @@
<add-roles <add-roles
v-model:visible="showRoles" v-model:visible="showRoles"
@on-success="onRefresh" @on-success="onRefresh"
:detail-id="detailId" :detail-id="selectMember?.id"
/> />
<!-- 权限抽屉 --> <!-- 权限抽屉 -->
<permission-drawer v-model:visible="showPermission" /> <permission-drawer v-model:visible="showPermission" :checkAuth="selectMember"/>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import dayjs from "dayjs"; import dayjs from "dayjs";
@@ -90,7 +90,8 @@ import CommonTable from "@/components/proTable/index.vue";
import memberSelector from "@/components/memberSelector/index.vue"; import memberSelector from "@/components/memberSelector/index.vue";
import addRoles from "./addRoles.vue"; import addRoles from "./addRoles.vue";
import permissionDrawer from "./permissionDrawer.vue"; import permissionDrawer from "./permissionDrawer.vue";
import { PermissionManage } from "@/dict"; import { DictManage } from "@/dict";
import { useDict } from '@/hooks/useDictData';
import { formatIndex } from "@/utils/utils"; import { formatIndex } from "@/utils/utils";
import { import {
getRoleList, getRoleList,
@@ -106,6 +107,7 @@ import {
} from "@/api/stage/permission/index.ts"; } from "@/api/stage/permission/index.ts";
import { useLocalManager } from "@/hooks/useLocalManager"; import { useLocalManager } from "@/hooks/useLocalManager";
defineOptions({ name: "PermissionManagement" }); defineOptions({ name: "PermissionManagement" });
const { dicts,refresh } = useDict('permission_list_enable_disable');
const activeTab = ref(1); const activeTab = ref(1);
const tableRef = ref(null); const tableRef = ref(null);
const searchVal = ref(""); const searchVal = ref("");
@@ -114,7 +116,6 @@ const memberList = ref([]); // 获取成员角色列表
const total = ref(0); const total = ref(0);
const showMember = ref(false); const showMember = ref(false);
const showRoles = ref(false); const showRoles = ref(false);
const detailId = ref("");
const showPermission = ref(false); const showPermission = ref(false);
const selectMember = ref({}); //当前选择的成员数量数据 const selectMember = ref({}); //当前选择的成员数量数据
const tabList = [ const tabList = [
@@ -208,13 +209,14 @@ const roleColumns = [
permission: ["*"], permission: ["*"],
onClick: (row) => { onClick: (row) => {
showPermission.value = true; showPermission.value = true;
selectMember.value = {...row};
}, },
}, },
{ {
label: "复制", label: "复制",
type: "default", type: "default",
link: true, link: true,
permission: ["edit"], permission: ["*"],
onClick: async (row) => { onClick: async (row) => {
try { try {
await copyRolePermission(row.id); await copyRolePermission(row.id);
@@ -229,17 +231,17 @@ const roleColumns = [
label: "编辑", label: "编辑",
type: "default", type: "default",
link: true, link: true,
permission: ["config"], permission: ["*"],
onClick: (row) => { onClick: (row) => {
showRoles.value = true; showRoles.value = true;
detailId.value = row.id; selectMember.value = {...row};
}, },
}, },
{ {
label: "删除", label: "删除",
type: "danger", type: "danger",
link: true, link: true,
permission: ["delete"], permission: ["*"],
disabledFn: (row) => { disabledFn: (row) => {
return row.type !== "SYSTEM"; return row.type !== "SYSTEM";
}, },
@@ -278,7 +280,7 @@ const tableColumns = computed(() => {
// 当前成员数量 // 当前成员数量
const addMember = (row) => { const addMember = (row) => {
showMember.value = true; showMember.value = true;
selectMember.value = row; selectMember.value = {...row};
getMemberList({ id: row.id }); getMemberList({ id: row.id });
}; };
@@ -309,7 +311,7 @@ watch(activeTab, () => {
tableRef.value && tableRef.value.reset(); tableRef.value && tableRef.value.reset();
}); });
// 权限 // 启用-停用
const handleDictStatus = async (row) => { const handleDictStatus = async (row) => {
try { try {
row.status === 1 ? await disableRole(row.id) : await enableRole(row.id); row.status === 1 ? await disableRole(row.id) : await enableRole(row.id);
@@ -366,10 +368,15 @@ const checkRolesText = computed(() => {
// 新增角色 // 新增角色
const addBtnClick = () => { const addBtnClick = () => {
if (activeTab.value === 1) { if (activeTab.value === 1) {
detailId.value = "";
showRoles.value = true; showRoles.value = true;
selectMember.value = {id:''}
} }
}; };
// 初始化
onMounted(() => {
refresh();
});
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.mj-permission-management { .mj-permission-management {

View File

@@ -20,7 +20,7 @@
/></el-icon> /></el-icon>
</div> </div>
<div class="sub-title"> <div class="sub-title">
正在为<span class="sub-roles">[超级管理员]&nbsp;</span>分配系统访问权限 正在为<span class="sub-roles">[{{ personAuth }}]&nbsp;</span>分配系统访问权限
</div> </div>
</div> </div>
<!-- 内容 --> <!-- 内容 -->
@@ -29,14 +29,12 @@
<div class="permission-container"> <div class="permission-container">
<el-tabs v-model="activeTab" class="custom-permission-tabs"> <el-tabs v-model="activeTab" class="custom-permission-tabs">
<el-tab-pane label="菜单权限" name="menu"> <el-tab-pane label="菜单权限" name="menu">
<base-segment-menu></base-segment-menu> <base-segment-menu :menuList="menuList"></base-segment-menu>
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="字段权限" name="field"> <el-tab-pane label="字段权限" name="field">
<fieldPermissionManager <fieldPermissionManager
v-model="currentModule" :dicts="dicts"
:modules="moduleList" v-model:field-groups-list="fieldsList"
v-model:field-groups="fieldsList"
@change="onModuleTabChange"
/> />
</el-tab-pane> </el-tab-pane>
</el-tabs> </el-tabs>
@@ -49,7 +47,7 @@
<div class="stats-info"></div> <div class="stats-info"></div>
<div class="actions"> <div class="actions">
<el-button link @click="drawerVisible = false">取消</el-button> <el-button link @click="drawerVisible = false">取消</el-button>
<el-button type="primary" class="btn-confirm">确认应用</el-button> <el-button type="primary" class="btn-confirm" @click="handleSavePermission" :loading="loading">确认应用</el-button>
</div> </div>
</div> </div>
</template> </template>
@@ -59,44 +57,160 @@
import { Close } from "@element-plus/icons-vue"; import { Close } from "@element-plus/icons-vue";
import baseSegmentMenu from "./baseSegmentMenu.vue"; import baseSegmentMenu from "./baseSegmentMenu.vue";
import fieldPermissionManager from "./fieldPermissionManager.vue"; import fieldPermissionManager from "./fieldPermissionManager.vue";
import { saveRolePermission,getRolePermission } from '@/api/stage/permission';
import { useDict } from '@/hooks/useDictData';
const { dicts,refresh } = useDict('permission_setting_status');
interface permissionProps {
permissions:Record<string,any>[];
}
defineOptions({ name: "PermissionDrawer" }); defineOptions({ name: "PermissionDrawer" });
const props = defineProps({
checkAuth:{
type: Object,
default: ()=>({}),
}
});
const drawerVisible = defineModel("visible", { type: Boolean, default: false }); const drawerVisible = defineModel("visible", { type: Boolean, default: false });
const activeTab = ref("menu"); const activeTab = ref<string>("menu");
const currentModule = ref(4); // 默认选中“商机详情” const currentModule = ref<number>(4); // 当前高亮的模块
const fieldsList = ref([ const menuList = ref([]);
{ const loading = ref<boolean>(false);
groupId: "g1", // 动态展示当前人员名称
groupName: "文本", const personAuth = computed(() => {
fields: [ return props.checkAuth.name;
{ id: "f1", name: "商机名称", permission: "read", collapsed: false }, });
{ id: "f2", name: "商机需求描述", permission: "read", collapsed: false },
],
},
{
groupId: "g2",
groupName: "选择",
fields: [
{ id: "f3", name: "合作类型", permission: "read", collapsed: false },
{ id: "f4", name: "需求品类", permission: "read", collapsed: false },
{ id: "f5", name: "线索/商机渠道", permission: "read", collapsed: false },
],
},
]);
const moduleList = [
{ id: 1, name: "线索详情" },
{ id: 2, name: "客户详情" },
{ id: 3, name: "工作室详情" },
{ id: 4, name: "商机详情" },
{ id: 5, name: "合同详情" },
{ id: 6, name: "项目详情" },
// ...以此类推
];
const onModuleTabChange = (id) => { // 动态的数据
console.log("切换到模块:", id); const fieldsList = computed({
// 这里可以调用接口更新 currentFields 的数据 get:()=>{
const activeFields = [];
menuList.value.forEach(group => {
(group.children || []).forEach(row => {
if (row.selected) {
activeFields.push(row); // 将包含 fields 的整个对象传过去
}
});
});
return activeFields;
},
set:()=>{}
})
// 获取角色详情数据
const roleDetail = async (roleId) =>{
try {
const response = await getRolePermission(roleId);
menuList.value = response.map(group => {
const checkedGroup = (group.children || []).filter(c => c.selected);
const checkedCount = checkedGroup.length;
return {
...group,
isIndeterminate: checkedCount > 0 && checkedCount < group.children.length,
children:(group.children||[]).map(child=>{
const actions = child.selected ? child.operations.filter(action => action.selected).map(action => action.id) : [];
return {
...child,
isIndeterminate: actions.length > 0 && actions.length < child.operations.length,
actions,
}; };
})
};
});
} catch (error) {
console.log('error',error);
}
}
/**
* 非阻塞提取权限载荷
* @param {Array} menuList 原始响应式数据
*/
const extractPermissionPayload = async (menuList) => {
// 使用深拷贝,避免清洗过程中由于响应式追踪导致的 UI 卡顿
const sourceData = JSON.parse(JSON.stringify(menuList));
const result = [];
// 辅助函数处理单个功能节点Leaf Node
const formatLeafNode = (node) => {
const operationIds = (node.actions || []);
const fieldPermissions = (node.fieldGroups || []).map(group => ({
groupId: group.id,
permission: group.permission,
fields: (group.fields || []).map(field => ({
fieldId: field.id,
permission: field.permission
}))
}));
return {
leafNodeId: node.id,
operationIds: operationIds,
fieldPermissions: fieldPermissions
};
};
return new Promise((resolve) => {
let i = 0;
const chunk = () => {
const startTime = performance.now();
// 保持每一片执行时间在 16ms 以内(一帧的时间),确保不卡顿
while (i < sourceData.length && (performance.now() - startTime) < 16) {
const group = sourceData[i];
// 情况 A: 有二级菜单 (如商机管理)
if (group.children && group.children.length > 0) {
group.children.forEach(row => {
// 只要有选中的操作或二级被选中,就视为有效节点
if (row.selected || (row.actions && row.actions.length > 0)) {
result.push(formatLeafNode(row));
}
});
}
// 情况 B: 一级就是功能节点 (如团队管理无children有operations)
else {
if (group.selected || group.actions && group.actions.length > 0) {
result.push(formatLeafNode(group));
}
}
i++;
}
if (i < sourceData.length) {
requestAnimationFrame(chunk);
} else {
resolve(result);
}
};
chunk();
});
};
watch(()=>menuList.value,(val)=>{
// console.log('获取数据动态变化',val);
},{deep:true})
// 保存权限
const handleSavePermission = async () =>{
try {
loading.value = true;
const finalPayload = await extractPermissionPayload(menuList.value);
const res = await saveRolePermission({roleId:props.checkAuth.id,permissions:finalPayload});
ElMessage.success('操作成功');
drawerVisible.value = false;
} catch (error) {
console.log('save error',error);
} finally {
loading.value = false;
}
}
// 监听传入的id值的变化
watch(drawerVisible,(newVisible)=>{
if(newVisible){
const newRoleId = props.checkAuth.id;
roleDetail(newRoleId);
refresh();
}
})
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@use "./baseSegmentedPermission.scss" as *; @use "./baseSegmentedPermission.scss" as *;

View File

@@ -0,0 +1,33 @@
import { componentMap } from "./routeMap";
/**
* 组装函数:将后端原始嵌套树重组为前端要求的骨架结构
* @param backendTree 后端返回的原始数据 (包含 backend, business 等顶层节点的树)
*/
export const transformBackendTree = (backendTree: any[]): any[] => {
if (!backendTree || !Array.isArray(backendTree)) return [];
// 排序操作
const sortedTree = [...backendTree].sort((a, b) => {
const sortA = a.sort ?? 999; // 兜底值,防止没有 sort 字段
const sortB = b.sort ?? 999;
return sortA - sortB;
});
return sortedTree.map(item => {
// 2. 构造当前节点
const newNode: any = {
...item,
code: componentMap[item.code],
originalCode: item.code, // 保留一份原始 code 备用
};
// 3. 递归处理 children
if (item.children && item.children.length > 0) {
newNode.children = transformBackendTree(item.children);
} else {
newNode.children = null;
}
return newNode;
});
};

View File

@@ -9,6 +9,7 @@ import TokenManager from "@/utils/storage";
import Login from "@/pages/Login/index.vue"; import Login from "@/pages/Login/index.vue";
import HomeView from "@/pages/Layout/index.vue"; import HomeView from "@/pages/Layout/index.vue";
import { transformBackendTree } from './generateFinalMenu';
import { mockBackendMenuData } from "@/mock/menu"; import { mockBackendMenuData } from "@/mock/menu";
const tokenManager = TokenManager.getInstance(); const tokenManager = TokenManager.getInstance();
// 基础路由(不需要权限验证) // 基础路由(不需要权限验证)
@@ -161,30 +162,9 @@ const addDynamicRoutes = async () => {
} }
try { try {
// 从后端获取路由菜单数据 (这边需要区分 后台的菜单 和用户的菜单) const { modules:backendRawData } = await getUserInfo();
let allRoutes: any[] = []; const allRoutes = transformBackendTree(backendRawData);
if (userStore.isBackendUser) { // console.log('获取最终渲染的菜单数据格式:',allRoutes);
const backendResponses = await getUserInfo();
console.log("获取当前的菜单数据信息:",backendResponses);
const backendResponse = [];
allRoutes = [
{
code: "stage",
name: "管理中心",
icon: "",
meta: {
title: "管理中心",
},
children: Object.keys(backendResponse).length
? backendResponse
: mockBackendMenuData,
},
];
} else {
// TODO:获取用户端的数据信息
// response = await getUserMenus();
allRoutes = [];
}
if (allRoutes) { if (allRoutes) {
// 转换路由数据 // 转换路由数据
const dynamicRoutes = transformRoutes( const dynamicRoutes = transformRoutes(

22
src/router/routeMap.ts Normal file
View File

@@ -0,0 +1,22 @@
const stageRoute = {
backend: "stage",
flow: "flow",
origanization: "origanization",
personnel: "personnel",
permission: "permission",
dict: "dict",
}
const businessRoute = {
business: "businessManage",
"business.customer": "customerManage",
"business.game_studio":"customerManage",
"business.opportunity":"customerManage",
}
export const componentMap: Record<string, string> = {
...stageRoute,
...businessRoute
};

View File

@@ -4,6 +4,7 @@ import AutoImport from "unplugin-auto-import/vite";
import Components from "unplugin-vue-components/vite"; import Components from "unplugin-vue-components/vite";
import { ElementPlusResolver } from "unplugin-vue-components/resolvers"; import { ElementPlusResolver } from "unplugin-vue-components/resolvers";
import { resolve } from "path"; import { resolve } from "path";
import vueJsx from '@vitejs/plugin-vue-jsx'
import { VITE_APP_BASE_API, VITE_PUBLIC_PATH } from './config.js'; import { VITE_APP_BASE_API, VITE_PUBLIC_PATH } from './config.js';
// https://vite.dev/config/ // https://vite.dev/config/
@@ -23,6 +24,7 @@ export default defineConfig(({ mode }) => {
resolvers: [ElementPlusResolver()], resolvers: [ElementPlusResolver()],
}), }),
vue(), vue(),
vueJsx()
], ],
resolve: { resolve: {
alias: { alias: {