DomainProject.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. <template>
  2. <div>
  3. <a-form-item :label="$t('dictionary.domain')" v-bind="formLayout" v-if="isAdminMode && l3PermissionEnable">
  4. <base-select
  5. ref="domain"
  6. v-decorator="decorators.domain"
  7. resource="domains"
  8. remote
  9. :is-default-select="isDefaultSelect"
  10. :params="domainParams"
  11. :select-props="{
  12. allowClear,
  13. labelInValue,
  14. placeholder: $t('rules.domain'),
  15. dropdownClassName: 'oc-select-dropdown',
  16. labelInValueKeyName: 'key',
  17. }"
  18. @change="domainChange"
  19. @update:resList="updateDomainList">
  20. <template #optionLabelTemplate="{ item }">
  21. <span class="text-color-secondary option-prefix">{{ $t('dictionary.domain') }}: </span>{{ item.name }}
  22. </template>
  23. </base-select>
  24. </a-form-item>
  25. <a-form-item :label="$t('cloudenv.resource_map_type')" :extra="resourceMapExtra">
  26. <a-checkbox-group v-decorator="extraDecorators.resource_map_type" :options="resourceMapTypeOpts" @change="resourceMapTypeChange" />
  27. </a-form-item>
  28. <a-form-item v-if="openProjectMapping" :label="$t('cloudenv.text_580')">
  29. <base-select
  30. v-decorator="extraDecorators.project_mapping_id"
  31. resource="project_mappings"
  32. showSync
  33. :select-props="{ placeholder: $t('common.tips.select', [$t('cloudenv.text_580')]) }"
  34. :params="projectMappingParams" />
  35. <div slot="extra">
  36. {{$t('cloudenv.no_project_mapping')}}
  37. <help-link :href="href">{{$t('cloudenv.go_create')}}</help-link>
  38. </div>
  39. </a-form-item>
  40. <a-form-item v-if="openProjectMapping" :label="$t('cloudenv.project_mapping_effective_scope')" :extra="effectiveScopeExtra">
  41. <a-radio-group v-decorator="extraDecorators.effective_scope" @change="effectiveScopeChange">
  42. <a-radio-button value="resource">{{$t('cloudenv.resource_tag')}}</a-radio-button>
  43. <a-radio-button value="project">{{$t('cloudenv.project_tag')}}</a-radio-button>
  44. </a-radio-group>
  45. </a-form-item>
  46. <a-form-item v-if="resourceMapType.length" :label="resourceMapType.length === 1 && resourceMapType.includes('project') ? $t('cloudenv.target_project') : $t('cloudenv.default_project')">
  47. <base-select
  48. ref="project"
  49. v-decorator="decorators.project"
  50. resource="projects"
  51. remote
  52. :is-default-select="isDefaultSelect"
  53. :params="projectParams"
  54. :select-props="{
  55. allowClear,
  56. labelInValue,
  57. placeholder: $t('rules.project'),
  58. dropdownClassName: 'oc-select-dropdown',
  59. labelInValueKeyName: 'key',
  60. }"
  61. @change="projectChange"
  62. @update:resList="updateProjectList">
  63. <template #optionLabelTemplate="{ item }">
  64. <span class="text-color-secondary option-prefix">{{ $t('dictionary.project') }}: </span>{{ item.name }}
  65. </template>
  66. </base-select>
  67. </a-form-item>
  68. </div>
  69. </template>
  70. <script>
  71. import * as R from 'ramda'
  72. import _ from 'lodash'
  73. import { mapGetters } from 'vuex'
  74. export default {
  75. name: 'DomainProject',
  76. props: {
  77. labelInValue: {
  78. type: Boolean,
  79. default: true,
  80. },
  81. decorators: {
  82. type: Object,
  83. validator: val => R.is(Array, val.domain) && R.is(Array, val.project),
  84. },
  85. fc: {
  86. type: Object,
  87. required: true,
  88. },
  89. allowClear: Boolean,
  90. formLayout: Object,
  91. provider: {
  92. type: String,
  93. },
  94. showAutoCreateProject: {
  95. type: Boolean,
  96. default: true,
  97. },
  98. isDefaultSelect: {
  99. type: Boolean,
  100. default: true,
  101. },
  102. cloneData: {
  103. type: Object,
  104. default: () => ({}),
  105. },
  106. },
  107. data () {
  108. const initResourceMapType = []
  109. const initProjectMapping = []
  110. let initEffectiveScope = ''
  111. const {
  112. auto_create_project,
  113. auto_create_project_for_provider,
  114. project_mapping_id,
  115. tenant,
  116. enable_resource_sync,
  117. enable_project_sync,
  118. } = this.cloneData
  119. if (auto_create_project_for_provider) initResourceMapType.push('cloudprovider')
  120. if (project_mapping_id) {
  121. initResourceMapType.push('project_mapping')
  122. initProjectMapping.push(project_mapping_id)
  123. }
  124. if (auto_create_project) initResourceMapType.push('external_project')
  125. if (tenant) {
  126. initResourceMapType.push('project')
  127. }
  128. if (enable_resource_sync && !initEffectiveScope) {
  129. initEffectiveScope = 'resource'
  130. } else if (enable_project_sync && !initEffectiveScope) {
  131. initEffectiveScope = 'project'
  132. }
  133. return {
  134. domains: [],
  135. domainParams: {
  136. scope: this.scope,
  137. limit: 20,
  138. filter: 'enabled.equals(1)', // 仅显示启用状态下的域
  139. },
  140. domainId: '',
  141. projectData: {},
  142. projects: [],
  143. disableProjectSelect: false,
  144. extraDecorators: {
  145. resource_map_type: [
  146. 'resource_map_type',
  147. {
  148. initialValue: initResourceMapType,
  149. rules: [{ required: true, message: this.$t('cloudenv.select_resource_map_type') }],
  150. },
  151. ],
  152. project_mapping_id: [
  153. 'project_mapping_id',
  154. {
  155. initialValue: initProjectMapping,
  156. rules: [{ required: true, message: this.$t('common.tips.select', [this.$t('cloudenv.text_580')]) }],
  157. },
  158. ],
  159. effective_scope: [
  160. 'effective_scope',
  161. {
  162. initialValue: initEffectiveScope || 'resource',
  163. },
  164. ],
  165. },
  166. resourceMapType: initResourceMapType,
  167. openProjectMapping: initResourceMapType.includes('project_mapping'),
  168. effectiveScope: initEffectiveScope || 'resource',
  169. }
  170. },
  171. computed: {
  172. ...mapGetters(['isAdminMode', 'scope', 'isDomainMode', 'userInfo', 'l3PermissionEnable']),
  173. isOpenstack () {
  174. if (this.provider) {
  175. return this.provider.toLowerCase() === 'openstack'
  176. }
  177. return false
  178. },
  179. resourceMapExtra () {
  180. const { resourceMapType } = this
  181. if (!resourceMapType.length) return ''
  182. if (resourceMapType.length === 1) {
  183. return this.$t(`cloudenv.resource_map_type.${resourceMapType[0]}`)
  184. }
  185. if (resourceMapType.includes('project_mapping') && resourceMapType.includes('external_project') && resourceMapType.includes('cloudprovider')) {
  186. return this.$t('cloudenv.resource_map_type.all')
  187. }
  188. if (resourceMapType.includes('project_mapping') && resourceMapType.includes('external_project')) {
  189. return this.$t('cloudenv.resource_map_type.project_mapping_and_external_project')
  190. }
  191. if (resourceMapType.includes('project_mapping') && resourceMapType.includes('cloudprovider')) {
  192. return this.$t('cloudenv.resource_map_type.project_mapping_and_cloudprovider')
  193. }
  194. if (resourceMapType.includes('external_project') && resourceMapType.includes('cloudprovider')) {
  195. return this.$t('cloudenv.resource_map_type.external_project_and_cloudprovider')
  196. }
  197. const types = resourceMapType.filter(key => key !== 'project')
  198. if (types.length) {
  199. return this.$t(`cloudenv.resource_map_type.${types[0]}`)
  200. } else {
  201. return this.$t('cloudenv.resource_map_type.project')
  202. }
  203. },
  204. effectiveScopeExtra () {
  205. if (this.effectiveScope === 'resource') {
  206. return this.$t('cloudenv.resource_tag_tip')
  207. }
  208. return this.$t('cloudenv.project_tag_tip')
  209. },
  210. href () {
  211. const url = this.$router.resolve('/projectmapping')
  212. return url.href
  213. },
  214. projectParams () {
  215. const ret = {
  216. scope: this.scope,
  217. limit: 20,
  218. }
  219. const domainId = this.domainId
  220. if (domainId && !this.isDomainMode) {
  221. ret.domain_id = domainId
  222. }
  223. if (this.isAdminMode) {
  224. delete ret.scope
  225. delete ret.domain_id
  226. ret.project_domain = domainId || this.userInfo.projectDomainId
  227. }
  228. return ret
  229. },
  230. projectMappingParams () {
  231. if (this.isAdminMode) {
  232. return {
  233. scope: this.scope,
  234. project_domain: this.domainId || this.userInfo.projectDomainId,
  235. }
  236. }
  237. return {
  238. scope: this.scope,
  239. }
  240. },
  241. resourceMapTypeOpts () {
  242. const ret = [
  243. { value: 'project_mapping', label: this.$t('cloudenv.belong_to_project.project_mapping') },
  244. { value: 'external_project', label: this.$t('cloudenv.belong_to_project.external_project') },
  245. { value: 'cloudprovider', label: this.$t('cloudenv.belong_to_project.cloudprovider') },
  246. { value: 'project', label: this.$t('cloudenv.target_project') },
  247. ]
  248. return ret
  249. },
  250. },
  251. mounted () {
  252. this.initDefaultData()
  253. },
  254. methods: {
  255. async initDefaultData () {
  256. if (this.isAdminMode) { // 系统视图
  257. let defaultDomain = { key: this.userInfo.projectDomainId, label: this.userInfo.projectDomain }
  258. const initialValue = _.get(this.decorators, 'domain[1].initialValue')
  259. if (R.is(Object, initialValue) && initialValue.key) {
  260. defaultDomain = { key: initialValue.key, label: initialValue.label }
  261. } else if (R.is(String, initialValue) && initialValue) {
  262. defaultDomain = { key: initialValue }
  263. }
  264. const projectInitialValue = _.get(this.decorators, 'project[1].initialValue')
  265. const domainChange = () => {
  266. this._setInitDomain(defaultDomain)
  267. this.domainChange(defaultDomain || {})
  268. }
  269. if (R.is(Object, projectInitialValue) && projectInitialValue.key) {
  270. domainChange()
  271. } else if (R.is(String, projectInitialValue) && projectInitialValue) {
  272. domainChange()
  273. } else {
  274. if (this.isDefaultSelect) {
  275. domainChange()
  276. }
  277. }
  278. if (this.isDomainFirstLoadData) {
  279. this.$emit('fetchDomainCallback')
  280. this.isDomainFirstLoadData = false
  281. }
  282. // await this.$nextTick()
  283. // this.$refs.domain.loadDefaultSelectedOpts()
  284. } else {
  285. if (this.isDomainMode) { // 域视图
  286. const data = [{
  287. key: this.userInfo.projectDomainId,
  288. label: this.userInfo.projectDomain,
  289. }]
  290. this.domains = data
  291. this.domainChange(data[0])
  292. let defaultProject = { key: this.userInfo.projectId, label: this.userInfo.projectName }
  293. const initialProject = _.get(this.decorators, 'project[1].initialValue')
  294. if (R.is(Object, initialProject) && initialProject.key) {
  295. defaultProject = { key: initialProject.key, label: initialProject.label }
  296. } else if (R.is(String, initialProject) && initialProject) {
  297. defaultProject = { key: initialProject.key, label: initialProject.label }
  298. }
  299. const projectChange = () => {
  300. this.projectChange(defaultProject || {})
  301. this._setInitProject(defaultProject || {})
  302. }
  303. if (R.is(Object, initialProject) && initialProject.key) {
  304. projectChange()
  305. } else if (R.is(String, initialProject) && initialProject) {
  306. projectChange()
  307. } else {
  308. if (this.isDefaultSelect) {
  309. projectChange()
  310. }
  311. }
  312. if (this.isProjectFirstLoadData) {
  313. this.$emit('fetchProjectCallback')
  314. this.isProjectFirstLoadData = false
  315. }
  316. } else { // 普通视图
  317. const data = [{
  318. key: this.userInfo.projectId,
  319. label: this.userInfo.projectName,
  320. }]
  321. this.projects = data
  322. // 普通视图下不用判断 isDefaultSelect
  323. this.projectChange(data[0])
  324. this._setInitProject(data[0])
  325. }
  326. }
  327. },
  328. resourceMapTypeChange (value) {
  329. this.resourceMapType = value
  330. this.openProjectMapping = value.includes('project_mapping')
  331. },
  332. effectiveScopeChange (e) {
  333. this.effectiveScope = e.target.value
  334. },
  335. /*
  336. * @params {Object} domain { key: <domainId> }
  337. */
  338. _setInitDomain (domain) {
  339. if (!R.isNil(domain) && !R.isEmpty(domain)) {
  340. if (this.labelInValue) {
  341. this.fc.setFieldsValue({
  342. domain: { key: domain.key, label: domain.label },
  343. })
  344. } else {
  345. this.fc.setFieldsValue({
  346. domain: domain.key,
  347. })
  348. }
  349. }
  350. },
  351. /*
  352. * @params {Object} project { key: <projectId> }
  353. */
  354. _setInitProject (project) {
  355. if (!R.isNil(project) && !R.isEmpty(project)) {
  356. if (this.labelInValue) {
  357. this.fc.setFieldsValue({
  358. project: { key: project.key, label: project.label },
  359. })
  360. } else {
  361. this.fc.setFieldsValue({
  362. project: project.key,
  363. })
  364. }
  365. }
  366. },
  367. /**
  368. * domain {Object|String}
  369. */
  370. domainChange (domain) {
  371. const domainId = R.is(Object, domain) ? domain.key : domain
  372. if (this.labelInValue) {
  373. this.$emit('update:domain', domain)
  374. } else {
  375. this.$emit('update:domain', domainId)
  376. }
  377. this.domainId = domainId
  378. },
  379. projectChange (project) {
  380. const projectId = R.is(Object, project) ? project.key : project
  381. this.projectData = project
  382. if (this.labelInValue) {
  383. this.$emit('update:project', project)
  384. } else {
  385. this.$emit('update:project', projectId)
  386. }
  387. },
  388. },
  389. }
  390. </script>