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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vue2server7",
3
- "version": "7.0.47",
3
+ "version": "7.0.49",
4
4
  "description": "",
5
5
  "scripts": {
6
6
  "dev": "nodemon --watch src --ext ts --exec \"ts-node src/app.ts\"",
@@ -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 / 路由权限 / 菜单权限。