vue2server7 7.0.47 → 7.0.49
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// scripts/check-permission-duplicate.js
|
|
2
|
+
import fs from 'fs'
|
|
3
|
+
import path from 'path'
|
|
4
|
+
|
|
5
|
+
const rootDir = path.resolve(process.cwd(), 'src')
|
|
6
|
+
|
|
7
|
+
const permissionMap = new Map()
|
|
8
|
+
|
|
9
|
+
function scanFile(filePath) {
|
|
10
|
+
const content = fs.readFileSync(filePath, 'utf-8')
|
|
11
|
+
|
|
12
|
+
// 匹配 v-permission="xxx" 或 v-permission="'xxx'"
|
|
13
|
+
const regex = /v-permission\s*=\s*["']([^"']+)["']/g
|
|
14
|
+
|
|
15
|
+
let match
|
|
16
|
+
while ((match = regex.exec(content))) {
|
|
17
|
+
const permission = match[1].trim()
|
|
18
|
+
|
|
19
|
+
if (!permissionMap.has(permission)) {
|
|
20
|
+
permissionMap.set(permission, [])
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
permissionMap.get(permission).push(filePath)
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function scanDir(dir) {
|
|
28
|
+
const files = fs.readdirSync(dir)
|
|
29
|
+
|
|
30
|
+
for (const file of files) {
|
|
31
|
+
const fullPath = path.join(dir, file)
|
|
32
|
+
const stat = fs.statSync(fullPath)
|
|
33
|
+
|
|
34
|
+
if (stat.isDirectory()) {
|
|
35
|
+
scanDir(fullPath)
|
|
36
|
+
} else if (/\.(vue|js|ts|jsx|tsx)$/.test(file)) {
|
|
37
|
+
scanFile(fullPath)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
scanDir(rootDir)
|
|
43
|
+
|
|
44
|
+
// 输出重复
|
|
45
|
+
console.log('\n🔍 重复的权限指令如下:\n')
|
|
46
|
+
|
|
47
|
+
let hasDuplicate = false
|
|
48
|
+
|
|
49
|
+
for (const [key, files] of permissionMap.entries()) {
|
|
50
|
+
if (files.length > 1) {
|
|
51
|
+
hasDuplicate = true
|
|
52
|
+
console.log(`🚨 权限:${key}`)
|
|
53
|
+
files.forEach(f => console.log(` - ${f}`))
|
|
54
|
+
console.log('')
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (!hasDuplicate) {
|
|
59
|
+
console.log('✅ 没有发现重复权限')
|
|
60
|
+
}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
# Vue3 按钮权限控制(自定义指令 + Pinia 版)
|
|
2
|
+
|
|
3
|
+
## 📌 目标
|
|
4
|
+
|
|
5
|
+
实现一套企业级按钮权限控制方案:
|
|
6
|
+
|
|
7
|
+
- ✔ 从 Pinia 获取权限
|
|
8
|
+
- ✔ 支持单权限 / 多权限
|
|
9
|
+
- ✔ 支持 AND / OR 逻辑
|
|
10
|
+
- ✔ 支持动态更新权限
|
|
11
|
+
- ✔ 全局指令 v-permission
|
|
12
|
+
- ✔ 自动响应权限变化
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
# 🧠 一、权限 Store(Pinia)
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
// stores/auth.ts
|
|
20
|
+
import { defineStore } from 'pinia'
|
|
21
|
+
|
|
22
|
+
export const useAuthStore = defineStore('auth', {
|
|
23
|
+
state: () => ({
|
|
24
|
+
permissions: [] as string[],
|
|
25
|
+
}),
|
|
26
|
+
|
|
27
|
+
actions: {
|
|
28
|
+
setPermissions(perms: string[]) {
|
|
29
|
+
this.permissions = perms
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
clearPermissions() {
|
|
33
|
+
this.permissions = []
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
})
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
# 🧩 二、权限判断工具函数
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
// utils/permission.ts
|
|
45
|
+
|
|
46
|
+
export type PermissionValue =
|
|
47
|
+
| string
|
|
48
|
+
| string[]
|
|
49
|
+
| { value: string[]; mode?: 'and' | 'or' }
|
|
50
|
+
|
|
51
|
+
export function hasPermission(
|
|
52
|
+
userPermissions: string[],
|
|
53
|
+
required?: PermissionValue
|
|
54
|
+
): boolean {
|
|
55
|
+
if (!required) return true
|
|
56
|
+
|
|
57
|
+
if (typeof required === 'string') {
|
|
58
|
+
return userPermissions.includes(required)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (Array.isArray(required)) {
|
|
62
|
+
return required.some(p => userPermissions.includes(p))
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const { value, mode = 'or' } = required
|
|
66
|
+
|
|
67
|
+
if (mode === 'and') {
|
|
68
|
+
return value.every(p => userPermissions.includes(p))
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return value.some(p => userPermissions.includes(p))
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
# ⚙️ 三、自定义指令 v-permission
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
// directives/permission.ts
|
|
81
|
+
import type { Directive } from 'vue'
|
|
82
|
+
import { useAuthStore } from '@/stores/auth'
|
|
83
|
+
import { hasPermission } from '@/utils/permission'
|
|
84
|
+
|
|
85
|
+
export const permission: Directive = {
|
|
86
|
+
mounted(el, binding) {
|
|
87
|
+
const authStore = useAuthStore()
|
|
88
|
+
|
|
89
|
+
const check = () => {
|
|
90
|
+
const ok = hasPermission(authStore.permissions, binding.value)
|
|
91
|
+
|
|
92
|
+
if (!ok) {
|
|
93
|
+
el.remove()
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
check()
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
updated(el, binding) {
|
|
101
|
+
const authStore = useAuthStore()
|
|
102
|
+
|
|
103
|
+
const ok = hasPermission(authStore.permissions, binding.value)
|
|
104
|
+
|
|
105
|
+
if (!ok) {
|
|
106
|
+
el.remove()
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
# 🚀 四、全局注册指令
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
// main.ts
|
|
118
|
+
import { createApp } from 'vue'
|
|
119
|
+
import App from './App.vue'
|
|
120
|
+
import { createPinia } from 'pinia'
|
|
121
|
+
import { permission } from '@/directives/permission'
|
|
122
|
+
|
|
123
|
+
const app = createApp(App)
|
|
124
|
+
|
|
125
|
+
app.use(createPinia())
|
|
126
|
+
|
|
127
|
+
app.directive('permission', permission)
|
|
128
|
+
|
|
129
|
+
app.mount('#app')
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
# 🧪 五、使用方式
|
|
135
|
+
|
|
136
|
+
## ✔ 单权限
|
|
137
|
+
|
|
138
|
+
```vue
|
|
139
|
+
<button v-permission="'user:add'">
|
|
140
|
+
新增用户
|
|
141
|
+
</button>
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## ✔ 多权限(OR)
|
|
147
|
+
|
|
148
|
+
```vue
|
|
149
|
+
<button v-permission="['user:add', 'user:edit']">
|
|
150
|
+
新增 / 编辑
|
|
151
|
+
</button>
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## ✔ AND 权限
|
|
157
|
+
|
|
158
|
+
```vue
|
|
159
|
+
<button
|
|
160
|
+
v-permission="{
|
|
161
|
+
value: ['user:add', 'user:delete'],
|
|
162
|
+
mode: 'and'
|
|
163
|
+
}"
|
|
164
|
+
>
|
|
165
|
+
必须同时拥有权限
|
|
166
|
+
</button>
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
# ⚠️ 六、常见问题
|
|
172
|
+
|
|
173
|
+
## ❌ Pinia 未初始化
|
|
174
|
+
|
|
175
|
+
```ts
|
|
176
|
+
let authStore: any
|
|
177
|
+
|
|
178
|
+
function getStore() {
|
|
179
|
+
if (!authStore) {
|
|
180
|
+
authStore = useAuthStore()
|
|
181
|
+
}
|
|
182
|
+
return authStore
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## ❌ 权限不更新
|
|
189
|
+
|
|
190
|
+
```ts
|
|
191
|
+
import { watch } from 'vue'
|
|
192
|
+
|
|
193
|
+
watch(
|
|
194
|
+
() => authStore.permissions,
|
|
195
|
+
() => {
|
|
196
|
+
// recheck
|
|
197
|
+
},
|
|
198
|
+
{ deep: true }
|
|
199
|
+
)
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
# 🎯 总结
|
|
205
|
+
|
|
206
|
+
适用于中后台系统的权限控制方案,支持扩展 RBAC / 路由权限 / 菜单权限。
|