index.vue 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. <template>
  2. <div class="app-action-menu">
  3. <teleport to="body" v-if="type === 'contextmenu'">
  4. <div class="app-action-menu__contextmenu" @contextmenu.prevent.capture @click="closeContextmenu"
  5. v-show="contextmenuOptions.show">
  6. <ul :style="styles">
  7. <li :class="item.className" v-for="(item, index) in actionMenus" :key="index"
  8. @click.stop="onClick(item, index)">
  9. <el-icon v-if="item.icon">
  10. <component :is="item.icon" />
  11. </el-icon>
  12. <span>{{ item.label }}</span>
  13. </li>
  14. </ul>
  15. </div>
  16. </teleport>
  17. <el-dropdown trigger="click" class="app-action-menu__dropdown" v-else-if="type === 'dropdown'">
  18. <el-button size="small" icon="MoreFilled" round />
  19. <template #dropdown>
  20. <el-dropdown-menu>
  21. <el-dropdown-item :class="item.className" v-for="(item, index) in actionMenus" :key="index"
  22. :icon="item.icon" @click.stop="onClick(item, index)">
  23. {{ item.label }}
  24. </el-dropdown-item>
  25. </el-dropdown-menu>
  26. </template>
  27. </el-dropdown>
  28. <div class="app-action-menu__btnbar" v-else>
  29. <template v-for="(item, index) in actionMenus" :key="index">
  30. <el-button :class="item.className" :type="item.type" :disabled="item.disabled"
  31. @click.stop="onClick(item, index)" :link="linkButton">
  32. <el-icon v-if="item.icon">
  33. <component :is="item.icon" />
  34. </el-icon>
  35. <span v-if="item.label">{{ item.label }}</span>
  36. </el-button>
  37. </template>
  38. </div>
  39. </div>
  40. </template>
  41. <script lang="ts" setup>
  42. import { ref, shallowRef, computed, PropType, watchEffect } from 'vue'
  43. import { ActionMenu } from './interface'
  44. const props = defineProps({
  45. // 操作菜单
  46. menus: {
  47. type: Array as PropType<Ermcp.UserMenu[]>,
  48. required: true,
  49. },
  50. // 操作类型
  51. type: {
  52. type: String as PropType<'button' | 'dropdown' | 'contextmenu'>,
  53. default: 'button',
  54. },
  55. // 右键菜单
  56. contextmenu: {
  57. type: Object as PropType<{ show: boolean; clientX: number; clientY: number; }>,
  58. default: () => ({
  59. show: false,
  60. clientX: 0,
  61. clientY: 0,
  62. }),
  63. },
  64. // 链接按钮
  65. linkButton: {
  66. type: Boolean,
  67. default: false,
  68. },
  69. record: Object,
  70. })
  71. const emit = defineEmits(['click'])
  72. const contextmenuOptions = shallowRef(props.contextmenu)
  73. const actionMenus = ref<ActionMenu[]>([])
  74. // 右键菜单坐标
  75. const styles = computed(() => {
  76. const { clientX, clientY } = contextmenuOptions.value
  77. return {
  78. left: clientX + 'px',
  79. top: clientY + 'px',
  80. }
  81. })
  82. // 关闭右键菜单
  83. const closeContextmenu = () => {
  84. contextmenuOptions.value.show = false
  85. }
  86. const onClick = (item: ActionMenu, index: number) => {
  87. item.record = props.record
  88. closeContextmenu()
  89. emit('click', item, index)
  90. }
  91. watchEffect(() => {
  92. actionMenus.value = props.menus.map((e) => ({
  93. name: e.code,
  94. label: e.title,
  95. icon: e.icon,
  96. className: e.className,
  97. hide: e.hidden,
  98. }))
  99. contextmenuOptions.value = props.contextmenu
  100. })
  101. </script>
  102. <style lang="less">
  103. @import './index.less';
  104. </style>