index.vue 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. <template>
  2. <div>
  3. <a-alert class="mb-2" :message="$t('cloudenv.project_mapping_rule_priority')" />
  4. <div class="d-flex flex-fill mb-2">
  5. <!-- 刷新 -->
  6. <a-button
  7. class="flex-shrink-0"
  8. :disabled="loading"
  9. @click="handleRefresh">
  10. <a-icon v-if="loading" type="sync" spin />
  11. <a-icon v-else type="sync" />
  12. </a-button>
  13. <actions
  14. :group="true"
  15. class="flex-shrink-0"
  16. :options="groupActions"
  17. button-type="default"
  18. :showSync="true"
  19. @clear-selected="() => $emit('clear-selected')" />
  20. </div>
  21. <vxe-grid
  22. v-bind="gridOptions"
  23. :columns="columns"
  24. row-key
  25. show-header-overflow
  26. highlight-hover-row
  27. highlight-current-row
  28. class="page-list-grid sortable-tree-demo"
  29. ref="grid"
  30. :tree-config="{children: 'children'}"
  31. @checkbox-change="checkboxChangeEvent"
  32. @checkbox-all="checkboxChangeEvent" />
  33. </div>
  34. </template>
  35. <script>
  36. import Sortable from 'sortablejs'
  37. import XEUtils from 'xe-utils'
  38. import { mapGetters } from 'vuex'
  39. import Actions from '@/components/PageList/Actions'
  40. import WindowsMixin from '@/mixins/windows'
  41. import ListMixin from '@/mixins/list'
  42. import ColumnsMixin from './columns'
  43. export default {
  44. name: 'ProjectMappingList',
  45. components: {
  46. Actions,
  47. },
  48. mixins: [WindowsMixin, ListMixin, ColumnsMixin],
  49. props: {
  50. id: String,
  51. data: Object,
  52. getParams: {
  53. type: Object,
  54. },
  55. },
  56. data () {
  57. return {
  58. gridOptions: {
  59. resizable: true,
  60. showOverflow: false,
  61. align: 'left',
  62. toolbarConfig: {
  63. slots: {
  64. buttons: 'toolbar_buttons',
  65. },
  66. },
  67. data: [],
  68. },
  69. groupNormalActions: [
  70. {
  71. label: this.$t('cloudenv.text_104'),
  72. permission: 'projectmappings_update',
  73. group: true,
  74. action: () => {
  75. this.createDialog('ProjectMappingRuleEditDialog', {
  76. id: this.data.id,
  77. projectDomainId: this.data.domain_id,
  78. editType: 'create',
  79. rules: this.data.rules,
  80. success: (res) => {
  81. this.$bus.$emit('ProjectMappingRuleUpdate', res)
  82. },
  83. })
  84. },
  85. meta: () => {
  86. if (!(this.isAdminMode || this.data.domain_id === this.userInfo.projectDomainId)) {
  87. return {
  88. validate: false,
  89. tooltip: this.$t('cloudenv.text_597'),
  90. }
  91. }
  92. return {
  93. buttonType: 'primary',
  94. }
  95. },
  96. },
  97. {
  98. label: this.$t('cloudenv.text_108'),
  99. permission: 'projectmappings_update',
  100. group: true,
  101. action: () => {
  102. // this.deleteProjectMappingRules()
  103. this.createDialog('DeleteResDialog', {
  104. name: this.$t('cloudenv.text_582'),
  105. vm: this,
  106. data: this.checkedRecords,
  107. columns: [this.normalColmns[0], this.normalColmns[1]],
  108. title: this.$t('table.action.delete'),
  109. ok: () => {
  110. this.deleteProjectMappingRules()
  111. },
  112. })
  113. },
  114. meta: () => {
  115. const ret = {
  116. validate: true,
  117. }
  118. if (!(this.isAdminMode || this.data.domain_id === this.userInfo.projectDomainId)) {
  119. ret.validate = false
  120. ret.tooltip = this.$t('cloudenv.text_597')
  121. }
  122. if (!this.checkedRecords.length || this.checkedRecords.length === (this.data.rules || []).length) {
  123. ret.validate = false
  124. }
  125. return ret
  126. },
  127. },
  128. {
  129. label: this.$t('cloudenv.text_601'),
  130. permission: 'projectmappings_update',
  131. group: true,
  132. action: () => {
  133. this.canSort = true
  134. this.gridOptions.data = [...this.initData]
  135. },
  136. meta: () => {
  137. if (!(this.isAdminMode || this.data.domain_id === this.userInfo.projectDomainId)) {
  138. return {
  139. validate: false,
  140. tooltip: this.$t('cloudenv.text_597'),
  141. }
  142. }
  143. return {
  144. validate: this.gridOptions.data.length > 1 && !this.canSort,
  145. }
  146. },
  147. },
  148. ],
  149. groupSaveActions: [
  150. {
  151. label: this.$t('cloudenv.text_599'),
  152. permission: 'projectmappings_update',
  153. group: true,
  154. action: () => {
  155. this.updateProjectMappingRules()
  156. },
  157. meta: () => {
  158. if (!(this.isAdminMode || this.data.domain_id === this.userInfo.projectDomainId)) {
  159. return {
  160. validate: false,
  161. tooltip: this.$t('cloudenv.text_597'),
  162. }
  163. }
  164. return {
  165. validate: this.canSort,
  166. }
  167. },
  168. },
  169. {
  170. label: this.$t('cloudenv.text_600'),
  171. permission: 'projectmappings_update',
  172. group: true,
  173. action: () => {
  174. this.canSort = false
  175. this.gridOptions.data = this.initData
  176. },
  177. meta: () => {
  178. if (!(this.isAdminMode || this.data.domain_id === this.userInfo.projectDomainId)) {
  179. return {
  180. validate: false,
  181. tooltip: this.$t('cloudenv.text_597'),
  182. }
  183. }
  184. return {
  185. validate: this.canSort,
  186. }
  187. },
  188. },
  189. ],
  190. canSort: false,
  191. checkedRecords: [],
  192. }
  193. },
  194. computed: {
  195. ...mapGetters(['isAdminMode', 'scope', 'isDomainMode', 'userInfo', 'l3PermissionEnable']),
  196. initData () {
  197. if (this.data.rules) {
  198. return this.data.rules.map(item => {
  199. return Object.assign(item, { can_delete: this.data.can_delete })
  200. })
  201. }
  202. return []
  203. },
  204. groupActions () {
  205. if (!this.canSort) {
  206. return [...this.groupNormalActions]
  207. } else {
  208. return [...this.groupNormalActions, ...this.groupSaveActions]
  209. }
  210. },
  211. },
  212. watch: {
  213. data: {
  214. handler: function () {
  215. this.gridOptions.data = [...this.initData]
  216. },
  217. deep: true,
  218. immediate: true,
  219. },
  220. },
  221. created () {
  222. this.treeDrop()
  223. },
  224. methods: {
  225. treeDrop () {
  226. this.$nextTick(() => {
  227. const xTable = this.$refs.grid
  228. this.sortable2 = Sortable.create(xTable.$el.querySelector('.body--wrapper>.vxe-table--body tbody'), {
  229. handle: '.drag-btn',
  230. onEnd: ({ item, oldIndex }) => {
  231. const options = { children: 'children' }
  232. const targetTrElem = item
  233. const wrapperElem = targetTrElem.parentNode
  234. const prevTrElem = targetTrElem.previousElementSibling
  235. const tableTreeData = this.gridOptions.data
  236. const selfRow = xTable.getRowNode(targetTrElem).item
  237. const selfNode = XEUtils.findTree(tableTreeData, row => row === selfRow, options)
  238. if (prevTrElem) {
  239. // 移动到节点
  240. const prevRow = xTable.getRowNode(prevTrElem).item
  241. const prevNode = XEUtils.findTree(tableTreeData, row => row === prevRow, options)
  242. if (XEUtils.findTree(selfRow[options.children], row => prevRow === row, options)) {
  243. // 错误的移动
  244. const oldTrElem = wrapperElem.children[oldIndex]
  245. wrapperElem.insertBefore(targetTrElem, oldTrElem)
  246. return this.$XModal.message({ content: '不允许自己给自己拖动!', status: 'error' })
  247. }
  248. const currRow = selfNode.items.splice(selfNode.index, 1)[0]
  249. if (xTable.isTreeExpandByRow(prevRow)) {
  250. // 移动到当前的子节点
  251. prevRow[options.children].splice(0, 0, currRow)
  252. } else {
  253. // 移动到相邻节点
  254. prevNode.items.splice(prevNode.index + (selfNode.index < prevNode.index ? 0 : 1), 0, currRow)
  255. }
  256. } else {
  257. // 移动到第一行
  258. const currRow = selfNode.items.splice(selfNode.index, 1)[0]
  259. tableTreeData.unshift(currRow)
  260. }
  261. // 如果变动了树层级,需要刷新数据
  262. this.gridOptions.data = [...tableTreeData]
  263. },
  264. })
  265. })
  266. },
  267. doUpdate (data) {
  268. return new this.$Manager('project_mappings').update({ id: this.data.id, data })
  269. },
  270. async updateProjectMappingRules () {
  271. try {
  272. await this.doUpdate({ rules: this.gridOptions.data })
  273. this.$bus.$emit('ProjectMappingRuleUpdate')
  274. this.canSort = false
  275. } catch (error) {
  276. throw error
  277. } finally {}
  278. },
  279. async deleteProjectMappingRules () {
  280. const params = []
  281. this.gridOptions.data.map(item => {
  282. let isHas = false
  283. this.checkedRecords.map(item2 => {
  284. if (item2._XID === item._XID) {
  285. isHas = true
  286. }
  287. })
  288. if (!isHas) {
  289. params.push(item)
  290. }
  291. })
  292. await this.doUpdate({ rules: params })
  293. this.$bus.$emit('ProjectMappingRuleUpdate')
  294. this.canSort = false
  295. this.checkedRecords = []
  296. },
  297. checkboxChangeEvent ({ records }) {
  298. this.checkedRecords = records
  299. },
  300. handleCustomList () {
  301. const grid = this.$refs.grid
  302. const cols = grid.getTableColumn().collectColumn || []
  303. let nameIndex = 0
  304. const hidenColumns = []
  305. if (cols.length) {
  306. const colType = cols[0].type
  307. nameIndex = colType === 'checkbox' ? 1 : 0
  308. hidenColumns.push(cols[nameIndex].property)
  309. }
  310. this.createDialog('CustomListDialog', {
  311. title: this.$t('common.text00011'),
  312. customs: grid.getTableColumn().collectColumn,
  313. hidenColumns,
  314. })
  315. },
  316. handleRefresh () {
  317. this.$bus.$emit('ProjectMappingRuleUpdate')
  318. },
  319. },
  320. }
  321. </script>
  322. <style lang="less">
  323. .sortable-tree-demo .drag-btn {
  324. cursor: move;
  325. font-size: 12px;
  326. }
  327. </style>