index.vue 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. <!-- 操作权限 -->
  2. <template>
  3. <div class="app-auth">
  4. <teleport to="body" v-if="type === 'contextmenu'">
  5. <div class="app-auth__contextmenu" @contextmenu.prevent.capture @click="closeContextmenu"
  6. v-show="contextmenuOption.show">
  7. <ul :style="styles">
  8. <li :class="item.code" v-for="(item, index) in dataList" :key="index"
  9. @click.stop="openComponent(item.code)">
  10. <el-icon v-if="item.icon">
  11. <component :is="item.icon" />
  12. </el-icon>
  13. <span>{{ item.title }}</span>
  14. </li>
  15. </ul>
  16. </div>
  17. </teleport>
  18. <div class="app-auth__button" v-else>
  19. <el-dropdown v-if="type === 'dropdown'">
  20. <el-button type="info" icon="Setting" />
  21. <template #dropdown>
  22. <el-dropdown-menu>
  23. <el-dropdown-item :class="item.code" v-for="(item, index) in dataList" :key="index"
  24. :icon="item.icon" @click="openComponent(item.code)">
  25. {{ item.title }}
  26. </el-dropdown-item>
  27. </el-dropdown-menu>
  28. </template>
  29. </el-dropdown>
  30. <ul v-else>
  31. <li v-for="(item, index) in dataList" :key="index">
  32. <el-button :class="item.code" :type="item.buttonType" :disabled="item.code === componentId"
  33. @click="openComponent(item.code)" :link="linkButton">
  34. <el-icon v-if="item.icon">
  35. <component :is="item.icon" />
  36. </el-icon>
  37. <span v-if="item.title">{{ item.title }}</span>
  38. </el-button>
  39. </li>
  40. </ul>
  41. </div>
  42. <component :is="componentMap.get(componentId)" :code="componentId" v-bind="options" @closed="closeComponent"
  43. v-if="componentId" />
  44. </div>
  45. </template>
  46. <script lang="ts" setup>
  47. import { onMounted, onUnmounted, onDeactivated, shallowRef, PropType, computed, watch } from 'vue'
  48. import { useAuth } from '@/hooks/auth'
  49. const emit = defineEmits(['click', 'closed'])
  50. const props = defineProps({
  51. code: String,
  52. // 组件参数
  53. options: Object,
  54. // 操作类型
  55. type: {
  56. type: String as PropType<'button' | 'dropdown' | 'contextmenu'>,
  57. default: 'button',
  58. },
  59. // 右键菜单
  60. contextmenu: {
  61. type: Object as PropType<{ show: boolean; clientX: number; clientY: number; }>,
  62. default: () => ({
  63. show: false,
  64. clientX: 0,
  65. clientY: 0,
  66. }),
  67. },
  68. // 链接按钮
  69. linkButton: {
  70. type: Boolean,
  71. default: false,
  72. },
  73. menus: {
  74. type: Array as PropType<string[]>,
  75. default: () => ([]),
  76. },
  77. })
  78. const { componentMap, getAuthButton } = useAuth(props.code);
  79. const componentId = shallowRef<string>();
  80. const contextmenuOption = shallowRef(props.contextmenu);
  81. const auth = shallowRef<Ermcp.UserMenu[]>([]);
  82. // 数据列表
  83. const dataList = computed(() => {
  84. if (props.menus.length) {
  85. return auth.value.filter((e) => props.menus.includes(e.code) || props.menus.includes(e.buttonName));
  86. } else {
  87. return auth.value;
  88. }
  89. })
  90. // 右键菜单坐标
  91. const styles = computed(() => {
  92. const { clientX, clientY } = contextmenuOption.value;
  93. return {
  94. left: clientX + 'px',
  95. top: clientY + 'px',
  96. }
  97. })
  98. // 关闭右键菜单
  99. const closeContextmenu = () => {
  100. contextmenuOption.value.show = false;
  101. }
  102. // 打开组件
  103. const openComponent = (code: string) => {
  104. closeContextmenu();
  105. componentId.value = code;
  106. emit('click', code);
  107. }
  108. // 关闭组件
  109. const closeComponent = (isCallback?: boolean) => {
  110. componentId.value = undefined;
  111. isCallback && emit('closed');
  112. }
  113. watch(() => props.contextmenu, (val) => contextmenuOption.value = val)
  114. onMounted(() => auth.value = getAuthButton())
  115. onUnmounted(() => closeComponent())
  116. onDeactivated(() => closeComponent())
  117. </script>
  118. <style lang="less">
  119. @import './index.less';
  120. </style>