Group.vue 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. <template>
  2. <div class="mb-3 group-wrap" :class="{ active: showContent }">
  3. <div class="d-flex">
  4. <div class="d-flex group-title" @click.stop.prevent="toggleContent">
  5. <div>{{ data.label }}</div>
  6. <div class="arrow-icon">
  7. <a-icon type="down" class="ml-2" />
  8. </div>
  9. </div>
  10. </div>
  11. <a-card v-if="showContent" class="mt-2">
  12. <template v-for="item of data.children">
  13. <div :key="item.key" class="d-flex mt-2 mb-2">
  14. <div class="title flex-grow-0 flex-shrink-0 text-truncate">{{ item.label }}</div>
  15. <div class="actions flex-fill">
  16. <template v-for="action of sortActions(item.actions)">
  17. <span
  18. v-if="!action.children"
  19. :key="action.key"
  20. class="mb-2 tag">{{ action.label }}</span>
  21. <a-button :key="action.key" v-else type="link" @click="showExtraAction(action.children)">{{ action.label }}</a-button>
  22. </template>
  23. </div>
  24. </div>
  25. </template>
  26. </a-card>
  27. </div>
  28. </template>
  29. <script>
  30. import * as R from 'ramda'
  31. import WindowsMixin from '@/mixins/windows'
  32. export default {
  33. mixins: [WindowsMixin],
  34. props: {
  35. data: {
  36. required: true,
  37. type: Object,
  38. },
  39. },
  40. data () {
  41. return {
  42. showContent: false,
  43. }
  44. },
  45. methods: {
  46. toggleContent () {
  47. this.showContent = !this.showContent
  48. },
  49. sortActions (actions) {
  50. const sortKeys = ['list', 'get', 'update', 'create', 'delete', 'perform']
  51. const sortActions = R.sort((a, b) => {
  52. return sortKeys.indexOf(a.key) - sortKeys.indexOf(b.key)
  53. }, actions)
  54. const normalActions = sortActions.filter(item => sortKeys.includes(item.key))
  55. // 将详细操作收起来
  56. const extraActions = sortActions.filter(item => !sortKeys.includes(item.key))
  57. if (extraActions.length) {
  58. normalActions.push({ key: 'extra', label: this.$t('iam.count_items', [extraActions.length]), children: extraActions })
  59. }
  60. return normalActions
  61. },
  62. showExtraAction (actions) {
  63. this.createDialog('PolicyExtraActionConfig', {
  64. title: this.$t(''),
  65. name: this.$t(''),
  66. resource: { disabled: true },
  67. actions: actions.map(item => ({ action: item.key, label: item.label })),
  68. checked: actions.map(action => action.key),
  69. isViewer: true,
  70. })
  71. },
  72. },
  73. }
  74. </script>
  75. <style lang="less" scoped>
  76. .group-title {
  77. width: 100px;
  78. cursor: pointer;
  79. }
  80. .active {
  81. .arrow-icon {
  82. > i {
  83. transform: rotate(180deg);
  84. }
  85. }
  86. }
  87. .group-wrap {
  88. .arrow-icon {
  89. > i {
  90. transition: transform .3s ease;
  91. }
  92. }
  93. }
  94. .title {
  95. width: 140px;
  96. }
  97. .tag {
  98. color: rgba(0,0,0,.65);
  99. height: auto;
  100. margin: 0 8px 0 0;
  101. padding: 2px 7px;
  102. line-height: 2;
  103. background: #fafafa;
  104. border: 1px solid #d9d9d9;
  105. }
  106. </style>