index.vue 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  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 trigger="click" v-if="type === 'dropdown'">
  20. <el-button size="small" icon="MoreFilled" round />
  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.className" :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, shallowRef, PropType, computed, watch } from 'vue'
  48. import { useMenu } from '@/hooks/menu'
  49. const emit = defineEmits(['click', 'closed'])
  50. const props = defineProps({
  51. code: String,
  52. // 组件参数
  53. options: Object,
  54. // 菜单列表
  55. menus: Array as PropType<string[]>,
  56. // 操作类型
  57. type: {
  58. type: String as PropType<'button' | 'dropdown' | 'contextmenu'>,
  59. default: 'button',
  60. },
  61. // 右键菜单
  62. contextmenu: {
  63. type: Object as PropType<{ show: boolean; clientX: number; clientY: number; }>,
  64. default: () => ({
  65. show: false,
  66. clientX: 0,
  67. clientY: 0,
  68. }),
  69. },
  70. // 链接按钮
  71. linkButton: {
  72. type: Boolean,
  73. default: false,
  74. },
  75. })
  76. const { componentMap, getAuthButtons } = useMenu(props.code);
  77. const componentId = shallowRef<string>();
  78. const contextmenuOption = shallowRef(props.contextmenu);
  79. const auth = shallowRef<Ermcp.UserRoutes[]>([]);
  80. // 数据列表
  81. const dataList = computed(() => {
  82. const menus = props.menus
  83. if (menus) {
  84. if (menus.length) {
  85. return auth.value.filter((e) => menus.includes(e.code) || menus.includes(e.buttonName));
  86. }
  87. return [];
  88. } else {
  89. return auth.value;
  90. }
  91. })
  92. // 右键菜单坐标
  93. const styles = computed(() => {
  94. const { clientX, clientY } = contextmenuOption.value;
  95. return {
  96. left: clientX + 'px',
  97. top: clientY + 'px',
  98. }
  99. })
  100. // 关闭右键菜单
  101. const closeContextmenu = () => {
  102. contextmenuOption.value.show = false;
  103. }
  104. // 打开组件
  105. const openComponent = (code: string) => {
  106. closeContextmenu();
  107. componentId.value = code;
  108. emit('click', code);
  109. }
  110. // 关闭组件
  111. const closeComponent = (isCallback?: boolean) => {
  112. componentId.value = undefined;
  113. isCallback && emit('closed');
  114. }
  115. watch(() => props.contextmenu, (val) => contextmenuOption.value = val)
  116. onMounted(() => auth.value = getAuthButtons())
  117. onUnmounted(() => closeComponent())
  118. </script>
  119. <style lang="less">
  120. @import './index.less';
  121. </style>