Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@

<script setup lang="ts" name="auth">
import { computed } from 'vue';
import { storeToRefs } from 'pinia';
import { useUserInfo } from '/@/stores/userInfo';
import { auth } from '/@/utils/authFunction';

// 定义父组件传过来的值
const props = defineProps({
Expand All @@ -15,12 +14,8 @@ const props = defineProps({
},
});

// 定义变量内容
const stores = useUserInfo();
const { userInfos } = storeToRefs(stores);

// 获取 pinia 中的用户权限
const getUserAuthBtnList = computed(() => {
return userInfos.value.authBtnList.some((v: string) => v === props.value);
return auth(props.value);
});
</script>
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@

<script setup lang="ts" name="authAll">
import { computed } from 'vue';
import { storeToRefs } from 'pinia';
import { useUserInfo } from '/@/stores/userInfo';
import { judementSameArr } from '/@/utils/arrayOperation';
import { authAll } from '/@/utils/authFunction';

// 定义父组件传过来的值
const props = defineProps({
Expand All @@ -16,12 +14,8 @@ const props = defineProps({
},
});

// 定义变量内容
const stores = useUserInfo();
const { userInfos } = storeToRefs(stores);

// 获取 pinia 中的用户权限
const getUserAuthBtnList = computed(() => {
return judementSameArr(props.value, userInfos.value.authBtnList);
return authAll(props.value);
});
</script>
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@

<script setup lang="ts" name="auths">
import { computed } from 'vue';
import { storeToRefs } from 'pinia';
import { useUserInfo } from '/@/stores/userInfo';
import { auths } from '/@/utils/authFunction';

// 定义父组件传过来的值
const props = defineProps({
Expand All @@ -15,18 +14,8 @@ const props = defineProps({
},
});

// 定义变量内容
const stores = useUserInfo();
const { userInfos } = storeToRefs(stores);

// 获取 pinia 中的用户权限
const getUserAuthBtnList = computed(() => {
let flag = false;
userInfos.value.authBtnList.map((val: string) => {
props.value.map((v) => {
if (val === v) flag = true;
});
});
return flag;
return auths(props.value);
});
</script>
126 changes: 82 additions & 44 deletions demo/WalkingTec.Mvvm.Vue3Demo/ClientApp/src/directive/authDirective.ts
Original file line number Diff line number Diff line change
@@ -1,44 +1,82 @@
import type { App } from 'vue';
import { useUserInfo } from '/@/stores/userInfo';
import { judementSameArr } from '/@/utils/arrayOperation';

/**
* 用户权限指令
* @directive 单个权限验证(v-auth="xxx")
* @directive 多个权限验证,满足一个则显示(v-auths="[xxx,xxx]")
* @directive 多个权限验证,全部满足则显示(v-auth-all="[xxx,xxx]")
*/
export function authDirective(app: App) {
// 单个权限验证(v-auth="xxx")
app.directive('auth', {
mounted(el, binding) {
const stores = useUserInfo();
if(stores.userInfos.isDebug == false){
if (!stores.userInfos.authBtnList.some((v: string) => {
return v.toLowerCase() === binding.value.toLowerCase()
})) el.parentNode.removeChild(el);
}
},
});
// 多个权限验证,满足一个则显示(v-auths="[xxx,xxx]")
app.directive('auths', {
mounted(el, binding) {
let flag = false;
const stores = useUserInfo();
stores.userInfos.authBtnList.map((val: string) => {
binding.value.map((v: string) => {
if (val === v) flag = true;
});
});
if (!flag) el.parentNode.removeChild(el);
},
});
// 多个权限验证,全部满足则显示(v-auth-all="[xxx,xxx]")
app.directive('auth-all', {
mounted(el, binding) {
const stores = useUserInfo();
const flag = judementSameArr(binding.value, stores.userInfos.authBtnList);
if (!flag) el.parentNode.removeChild(el);
},
});
}
import { watch } from 'vue';
import type { App, ObjectDirective } from 'vue';
import { useUserInfo } from '/@/stores/userInfo';
import { auth, authAll, auths } from '/@/utils/authFunction';

type PermissionCheck = (value: unknown) => boolean;

interface PermissionElementState {
bindingValue: unknown;
checkPermission: PermissionCheck;
wasInitiallyHidden: HTMLElement['hidden'];
}

// 注册所有使用权限指令的元素。这里只保存元素状态,不为每个元素创建 watcher。
// Map 需要在 unmounted 中主动删除,避免继续持有已经卸载的 DOM。
const permissionElements = new Map<HTMLElement, PermissionElementState>();
let stopWatchingPermissions: (() => void) | undefined;

function updateElementVisibility(el: HTMLElement, state: PermissionElementState) {
const shouldHide = state.wasInitiallyHidden || !state.checkPermission(state.bindingValue);
if (el.hidden !== shouldHide) el.hidden = shouldHide;
}

function updateAllPermissionElements() {
permissionElements.forEach((state, el) => updateElementVisibility(el, state));
}

function startWatchingPermissions() {
if (stopWatchingPermissions) return;

const stores = useUserInfo();
stopWatchingPermissions = watch(
[() => stores.userInfos.isDebug, () => stores.authBtnSet],
updateAllPermissionElements
);
}

function createPermissionDirective(checkPermission: PermissionCheck): ObjectDirective<HTMLElement, unknown> {
return {
mounted(el, binding) {
const state = {
bindingValue: binding.value,
checkPermission,
wasInitiallyHidden: el.hidden,
};
permissionElements.set(el, state);
updateElementVisibility(el, state);
startWatchingPermissions();
},
updated(el, binding) {
const state = permissionElements.get(el);
if (!state) return;

state.bindingValue = binding.value;
updateElementVisibility(el, state);
},
unmounted(el) {
permissionElements.delete(el);

// 页面上已经没有权限指令时,连唯一的共享 watcher 也一起释放。
if (permissionElements.size === 0) {
stopWatchingPermissions?.();
stopWatchingPermissions = undefined;
}
},
};
}

/**
* 用户权限指令
* @directive 单个权限验证(v-auth="xxx")
* @directive 多个权限验证,满足一个则显示(v-auths="[xxx,xxx]")
* @directive 多个权限验证,全部满足则显示(v-auth-all="[xxx,xxx]")
*/
export function authDirective(app: App) {
// 单个权限验证(v-auth="xxx")
app.directive('auth', createPermissionDirective(auth));
// 多个权限验证,满足一个则显示(v-auths="[xxx,xxx]")
app.directive('auths', createPermissionDirective(auths));
// 多个权限验证,全部满足则显示(v-auth-all="[xxx,xxx]")
app.directive('auth-all', createPermissionDirective(authAll));
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,15 @@ export const useUserInfo = defineStore('userInfo', {
menu:[],
roles: [],
authBtnList: [],
},
}),
getters: {
// Pinia getter 会缓存结果,仅在 authBtnList 变化时重新生成。
// 权限指令和组件可以复用同一个 Set,避免每个按钮重复遍历权限数组。
authBtnSet: (state): Set<string> => {
return new Set(state.userInfos.authBtnList.map((value) => value.trim().toLowerCase()).filter(Boolean));
},
}),
},
actions: {
async setUserInfos() {
// 存储用户信息到浏览器缓存
Expand Down
25 changes: 12 additions & 13 deletions demo/WalkingTec.Mvvm.Vue3Demo/ClientApp/src/utils/authFunction.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,37 @@
import { useUserInfo } from '/@/stores/userInfo';
import { judementSameArr } from '/@/utils/arrayOperation';

/**
* 单个权限验证
* @param value 权限值
* @returns 有权限,返回 `true`,反之则反
*/
export function auth(value: string): boolean {
export function auth(value: unknown): boolean {
if (typeof value !== 'string') return false;
const stores = useUserInfo();
return stores.userInfos.authBtnList.some((v: string) => v === value);
if (stores.userInfos.isDebug === true) return true;
return stores.authBtnSet.has(value.trim().toLowerCase());
}

/**
* 多个权限验证,满足一个则为 true
* @param value 权限值
* @returns 有权限,返回 `true`,反之则反
*/
export function auths(value: Array<string>): boolean {
let flag = false;
export function auths(value: unknown): boolean {
if (!Array.isArray(value) || !value.every((item) => typeof item === 'string')) return false;
const stores = useUserInfo();
stores.userInfos.authBtnList.map((val: string) => {
value.map((v: string) => {
if (val === v) flag = true;
});
});
return flag;
if (stores.userInfos.isDebug === true) return true;
return value.some((permission) => stores.authBtnSet.has(permission.trim().toLowerCase()));
}

/**
* 多个权限验证,全部满足则为 true
* @param value 权限值
* @returns 有权限,返回 `true`,反之则反
*/
export function authAll(value: Array<string>): boolean {
export function authAll(value: unknown): boolean {
if (!Array.isArray(value) || !value.every((item) => typeof item === 'string')) return false;
const stores = useUserInfo();
return judementSameArr(value, stores.userInfos.authBtnList);
if (stores.userInfos.isDebug === true) return true;
return value.length > 0 && value.every((permission) => stores.authBtnSet.has(permission.trim().toLowerCase()));
}