index.vue 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. <template>
  2. <div>
  3. <a-form :form="form.fc" v-bind="formItemLayout" layout="vertical">
  4. <div class="d-flex" v-for="(item, i) in resourceList" :key="item.key">
  5. <a-form-item class="mr-2" :label="i > 0 ? '' : $t('k8s.text_64')">
  6. <base-select
  7. style="width: 300px"
  8. v-decorator="decorators.resources(item.key)"
  9. :options="resourceOpts"
  10. filterable
  11. @update:item="val => syncItem(val, item)"
  12. :select-props="{ placeholder: $t('k8s.text_380') }" />
  13. </a-form-item>
  14. <a-form-item :labelCol="{ span: 24 }" style="min-width: 200px;" :label="i > 0 ? '' : $t('k8s.text_381')" class="verbs-item">
  15. <div v-if="!item.verbs.length" class="no-verbs-tip">{{$t('k8s.text_382')}}</div>
  16. <a-checkbox-group v-else v-decorator="decorators.verbs(item.key)" name="checkboxgroup" :options="item.verbs" />
  17. </a-form-item>
  18. <a-button shape="circle" icon="minus" size="small" @click="decrease(i)" :class="i === 0 ? 'mt-4_5': ''" />
  19. </div>
  20. <div class="d-flex align-items-center">
  21. <a-button type="primary" shape="circle" icon="plus" size="small" @click="add" />
  22. <a-button type="link" @click="add">{{$t('k8s.text_383')}}</a-button>
  23. </div>
  24. </a-form>
  25. </div>
  26. </template>
  27. <script>
  28. import * as R from 'ramda'
  29. import { uuid } from '@/utils/utils'
  30. export default {
  31. name: 'RoleRuleFormItem',
  32. props: {
  33. clusterId: {
  34. type: String,
  35. },
  36. isNamespace: {
  37. type: Boolean,
  38. default: false,
  39. },
  40. federatedResource: {
  41. type: String,
  42. },
  43. },
  44. data () {
  45. return {
  46. form: {
  47. fc: this.$form.createForm(this, { name: 'time_related_controls' }),
  48. },
  49. resourceList: [],
  50. formItemLayout: {
  51. labelCol: {
  52. xs: { span: 24 },
  53. sm: { span: 8 },
  54. },
  55. wrapperCol: {
  56. xs: { span: 24 },
  57. sm: { span: 16 },
  58. },
  59. },
  60. decorators: {
  61. resources: i => [
  62. `resources[${i}]`,
  63. {
  64. rules: [
  65. { required: true, message: this.$t('k8s.text_380') },
  66. ],
  67. },
  68. ],
  69. apiGroups: i => [
  70. `apiGroups[${i}]`,
  71. {
  72. initialValue: '*',
  73. normalize: value => {
  74. if (!value) return ''
  75. return value
  76. },
  77. },
  78. ],
  79. verbs: i => [
  80. `verbs[${i}]`,
  81. {
  82. rules: [
  83. { required: true, message: this.$t('k8s.text_384') },
  84. ],
  85. },
  86. ],
  87. },
  88. resourceOpts: [],
  89. }
  90. },
  91. watch: {
  92. clusterId () {
  93. this.fetchData()
  94. },
  95. },
  96. created () {
  97. if (this.federatedResource) {
  98. this.fetchFederatedData()
  99. } else {
  100. this.fetchData()
  101. }
  102. },
  103. methods: {
  104. syncItem (val, item) {
  105. item.verbs = val.verbs
  106. },
  107. async fetchFederatedData () {
  108. try {
  109. const { data = [] } = await new this.$Manager(this.federatedResource, 'v1').get({ id: 'api-resources', params: { scope: this.$store.getters.scope } })
  110. this.getResourceOpts(data)
  111. } catch (error) {
  112. throw error
  113. }
  114. },
  115. async fetchData () {
  116. try {
  117. if (!this.clusterId) return
  118. const { data = [] } = await new this.$Manager('kubeclusters', 'v1').getSpecific({ id: this.clusterId, spec: 'api-resources', params: { scope: this.$store.getters.scope } })
  119. this.getResourceOpts(data)
  120. } catch (error) {
  121. throw error
  122. }
  123. },
  124. getResourceOpts (data) {
  125. if (this.isNamespace) data = data.filter(val => val.apiResource.namespaced)
  126. data = data.map(val => {
  127. let label = val.apiResource.name
  128. if (val.apiGroup) label = `${val.apiGroup} / ${label}`
  129. return {
  130. key: `${val.apiGroup} / ${val.apiResource.name}`,
  131. label,
  132. verbs: val.apiResource.verbs,
  133. }
  134. })
  135. this.resourceOpts = data
  136. },
  137. async validateForm () {
  138. try {
  139. const values = await this.form.fc.validateFields()
  140. const data = {
  141. rules: [],
  142. }
  143. R.forEachObjIndexed((value, key) => {
  144. const [apiGroup, resouce] = value.split(' / ')
  145. data.rules.push({
  146. apiGroups: [apiGroup],
  147. resources: [resouce],
  148. verbs: values.verbs[key],
  149. })
  150. }, values.resources)
  151. return data
  152. } catch (error) {
  153. throw error
  154. }
  155. },
  156. decrease (i) {
  157. this.resourceList.splice(i, 1)
  158. },
  159. add () {
  160. this.resourceList.push({
  161. key: uuid(),
  162. verbs: [],
  163. })
  164. },
  165. },
  166. }
  167. </script>
  168. <style lang="less" scoped>
  169. @import '../../../../src/styles/less/theme';
  170. .mt-4_5 {
  171. margin-top: 1.8rem;
  172. }
  173. .verbs-item {
  174. /deep/ .ant-form-item-control-wrapper {
  175. span.ant-form-item-children {
  176. display: inline-block;
  177. .no-verbs-tip {
  178. font-size: 12px;
  179. color: @text-color-secondary;
  180. margin-top: 0.5rem;
  181. }
  182. }
  183. }
  184. }
  185. </style>