index.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  1. <template>
  2. <a-spin :spinning="loading">
  3. <page-header :title="title" />
  4. <page-body>
  5. <template v-if="isUpdate">
  6. <a-alert class="mb-2" :message="$t('system.text_230')" />
  7. </template>
  8. <template v-if="isUpdate">
  9. <idp-detail-table :data="[detailData]" />
  10. </template>
  11. <a-form :form="form.fc" v-bind="formItemLayout">
  12. <template v-if="!isUpdate">
  13. <template v-if="isAdmin">
  14. <a-form-item :label="$t('common_548')">
  15. <a-radio-group v-model="isShowDomain">
  16. <a-radio-button :value="false">{{$t('system.text_15')}}</a-radio-button>
  17. <a-radio-button :value="true">{{$t('dictionary.domain')}}</a-radio-button>
  18. </a-radio-group>
  19. </a-form-item>
  20. <a-form-item v-if="isAdmin && isShowDomain" :label="$t('common_547', [$t('dictionary.domain')])">
  21. <base-select
  22. v-decorator="decorators.project_domain"
  23. @change="handleDomain"
  24. resource="domains"
  25. filterable
  26. :params="{limit: 20}"
  27. version="v1"
  28. :select-props="{
  29. placeholder: $t('common_515', [$t('dictionary.domain')])
  30. }" />
  31. </a-form-item>
  32. </template>
  33. <a-form-item v-else :label="$t('common_566', [$t('dictionary.domain')])">
  34. {{projectDomain}}
  35. </a-form-item>
  36. <a-form-item :label="$t('common_186')">
  37. <a-input v-decorator="decorators.name" :placeholder="$t('common_549')" />
  38. </a-form-item>
  39. <a-form-item :label="$t('common.description')">
  40. <a-textarea :auto-size="{ minRows: 1, maxRows: 3 }" v-decorator="decorators.description" :placeholder="$t('common_367')" />
  41. </a-form-item>
  42. <a-form-item :label="$t('system.text_204')">
  43. <a-radio-group @change="({ target })=> driverChange(target.value)" v-decorator="decorators.driver">
  44. <a-radio-button v-for="(item, key) of templateOptions" :key="key" :value="key">
  45. {{key}}
  46. </a-radio-button>
  47. </a-radio-group>
  48. </a-form-item>
  49. <a-form-item :label="$t('common_550')">
  50. <a-radio-group v-decorator="decorators.template" @change="handleTemplateChange">
  51. <template v-for="(item) of templateOptions[form.fd.driver]">
  52. <a-radio-button
  53. :value="item.key"
  54. :key="item.key">{{ item.label }}</a-radio-button>
  55. </template>
  56. </a-radio-group>
  57. <template v-if="docLink" #extra>
  58. {{$t('common_709', [templateData.label])}}
  59. <help-link :href="docLink">{{$t('common_386')}}</help-link>
  60. </template>
  61. </a-form-item>
  62. <template v-if="isLdap && (form.fd.template === 'msad_one_domain' || form.fd.template === 'openldap_one_domain')">
  63. <ldap-advanced
  64. :is-common="isCommon"
  65. :fd="form.fd"
  66. :fc="form.fc"
  67. :template-data="templateData"
  68. :offset-wrapper-col="offsetWrapperCol" />
  69. </template>
  70. </template>
  71. <component
  72. :is="form.fd.template"
  73. :decorators="decorators[form.fd.template]"
  74. :fd="form.fd"
  75. :offset-wrapper-col="offsetWrapperCol"
  76. :fc="form.fc" />
  77. <template v-if="!isUpdate">
  78. <a-form-item v-if="isLdap" :label="$t('system.text_223')" :extra="$t('system.text_224')">
  79. <a-radio-group v-decorator="decorators.disable_user_on_import">
  80. <a-radio-button :value="false">{{$t('status.enabled.true')}}</a-radio-button>
  81. <a-radio-button :value="true">{{$t('status.enabled.false')}}</a-radio-button>
  82. </a-radio-group>
  83. </a-form-item>
  84. <advanced
  85. v-if="!isLdap"
  86. :is-common="isCommon"
  87. :fd="form.fd"
  88. :fc="form.fc"
  89. :template-data="templateData"
  90. :offset-wrapper-col="offsetWrapperCol" />
  91. </template>
  92. </a-form>
  93. </page-body>
  94. <page-footer>
  95. <template v-slot:right>
  96. <a-button type="primary" :loading="submiting" @click="handleSubmit">{{ $t('dialog.ok') }}</a-button>
  97. <a-button class="ml-3" @click="handleCancel">{{ $t('dialog.cancel') }}</a-button>
  98. </template>
  99. </page-footer>
  100. </a-spin>
  101. </template>
  102. <script>
  103. import * as R from 'ramda'
  104. import jumper from '@/mixins/jumper'
  105. import { resolveValueChangeField } from '@/utils/common/ant'
  106. import { docs, idpDrivers } from '../constants'
  107. import IDPDetailTable from '../components/DetailTable'
  108. import MSADMulti from './MSADMulti'
  109. import MSADOne from './MSADOne'
  110. import OpenLdapOne from './OpenLdapOne'
  111. import Advanced from './Advanced'
  112. import LdapAdvanced from './LdapAdvanced'
  113. export default {
  114. name: 'IDPEdit',
  115. components: {
  116. Advanced,
  117. msad_one_domain: MSADOne,
  118. msad_multi_domain: MSADMulti,
  119. openldap_one_domain: OpenLdapOne,
  120. 'idp-detail-table': IDPDetailTable,
  121. LdapAdvanced,
  122. },
  123. mixins: [jumper],
  124. data () {
  125. const templateInitialValue = 'msad_one_domain'
  126. const driverInitialValue = 'LDAP'
  127. return {
  128. loading: false,
  129. submiting: false,
  130. isShowDomain: false,
  131. isAdmin: this.$store.getters.isAdminMode,
  132. isDomainMode: this.$store.getters.isDomainMode,
  133. projectDomain: this.$store.getters.userInfo.projectDomain,
  134. projectDomainId: this.$store.getters.userInfo.projectDomainId,
  135. form: {
  136. fc: this.$form.createForm(this, {
  137. onValuesChange: (props, values) => {
  138. this.$nextTick(() => {
  139. const newField = resolveValueChangeField(values)
  140. R.forEachObjIndexed((item, key) => {
  141. this.$set(this.form.fd, key, item)
  142. }, newField)
  143. })
  144. },
  145. }),
  146. fd: {
  147. template: templateInitialValue,
  148. driver: driverInitialValue,
  149. },
  150. },
  151. decorators: {
  152. driver: [
  153. 'driver',
  154. {
  155. initialValue: driverInitialValue,
  156. },
  157. ],
  158. name: [
  159. 'name',
  160. {
  161. rules: [
  162. { required: true, message: this.$t('system.text_168') },
  163. ],
  164. },
  165. ],
  166. description: ['description'],
  167. project_domain: [
  168. 'project_domain',
  169. {
  170. rules: [
  171. { required: true, message: this.$t('common_523', [this.$t('dictionary.domain')]) },
  172. ],
  173. },
  174. ],
  175. template: [
  176. 'template',
  177. {
  178. initialValue: templateInitialValue,
  179. },
  180. ],
  181. disable_user_on_import: [
  182. 'disable_user_on_import',
  183. {
  184. initialValue: false,
  185. },
  186. ],
  187. },
  188. formItemLayout: {
  189. wrapperCol: {
  190. span: 18,
  191. xxl: {
  192. span: 20,
  193. },
  194. },
  195. labelCol: {
  196. span: 5,
  197. xxl: {
  198. span: 4,
  199. },
  200. },
  201. },
  202. offsetWrapperCol: {
  203. wrapperCol: {
  204. offset: 5,
  205. xxl: {
  206. offset: 4,
  207. },
  208. },
  209. },
  210. detailData: {},
  211. }
  212. },
  213. computed: {
  214. id () {
  215. return this.$route.params.id
  216. },
  217. isUpdate () {
  218. return !!this.id
  219. },
  220. isLdap () {
  221. return this.form.fd.driver === 'LDAP'
  222. },
  223. title () {
  224. if (this.isUpdate) return this.$t('system.text_563')
  225. return this.$t('system.text_562')
  226. },
  227. templateData () {
  228. const { driver, template } = this.form.fd
  229. if (this.templateOptions && this.templateOptions[driver]) {
  230. return this.templateOptions[driver].find(({ key }) => key === template)
  231. }
  232. return {}
  233. },
  234. // 是否为通用模版
  235. isCommon () {
  236. const { template } = this.form.fd
  237. return ['oidc', 'saml', 'cas'].indexOf(template) > -1
  238. },
  239. templateOptions () {
  240. const templateOptions = {}
  241. Object.keys(idpDrivers).forEach(key => {
  242. templateOptions[key] = []
  243. Object.values(idpDrivers[key]).forEach(tkey => {
  244. templateOptions[key].push({
  245. label: this.$t(`idpTmplTitles.${tkey}`),
  246. key: tkey,
  247. })
  248. })
  249. })
  250. // 认证源归属为域时,删除ldap多域导入选项
  251. if (this.isShowDomain) {
  252. const index = R.findIndex(R.propEq('key', 'msad_multi_domain'))(templateOptions.LDAP)
  253. templateOptions.LDAP = R.remove(index, 1, templateOptions.LDAP)
  254. }
  255. return templateOptions
  256. },
  257. docLink () {
  258. return this.templateData && docs(this.$store.getters.scope)[this.templateData.key]
  259. },
  260. },
  261. watch: {
  262. isShowDomain (val) {
  263. if (val && this.form.fd.template === 'msad_multi_domain') {
  264. this.form.fc.setFieldsValue({
  265. template: 'msad_one_domain',
  266. })
  267. }
  268. },
  269. },
  270. destroyed () {
  271. this.manager = null
  272. },
  273. created () {
  274. this.manager = new this.$Manager('identity_providers', 'v1')
  275. if (this.isUpdate) {
  276. this.fetchInfo()
  277. } else {
  278. this.driverChange()
  279. }
  280. },
  281. methods: {
  282. handleDomain (domainId) {
  283. this.form.fc.setFieldsValue({
  284. target_domain: domainId,
  285. })
  286. },
  287. scopesFormat (value, f) {
  288. if (value) {
  289. if (f) {
  290. return value.join(',')
  291. }
  292. return value.split(',')
  293. }
  294. return f ? '' : []
  295. },
  296. async fetchDetail () {
  297. try {
  298. const { data } = await this.manager.get({
  299. id: this.id,
  300. params: {
  301. detail: true,
  302. },
  303. })
  304. this.detailData = data
  305. this.form.fc.getFieldDecorator('template', { preserve: true })
  306. this.form.fc.setFieldsValue({
  307. template: data.template || data.driver,
  308. })
  309. } catch (err) {
  310. throw err
  311. }
  312. },
  313. async fetchConfig () {
  314. try {
  315. const { data = {} } = await this.manager.getSpecific({
  316. id: this.id,
  317. spec: 'config',
  318. })
  319. const { config = {} } = data
  320. await this.$nextTick()
  321. const key = Object.keys(config)[0]
  322. const params = {
  323. ...config[key],
  324. }
  325. if (params.scopes) {
  326. params.scopes = this.scopesFormat(params.scopes, true)
  327. }
  328. if (params.template === 'qywechat_oauth2') {
  329. const [corp_id, agent_id] = params.app_id.split('/')
  330. params.corp_id = corp_id
  331. params.agent_id = agent_id
  332. delete params.app_id
  333. }
  334. this.form.fc.getFieldDecorator('driver', { preserve: true })
  335. this.form.fc.setFieldsValue({
  336. driver: key,
  337. ...params,
  338. })
  339. } catch (err) {
  340. throw err
  341. }
  342. },
  343. async fetchInfo () {
  344. this.loading = true
  345. try {
  346. await this.fetchDetail()
  347. await this.fetchConfig()
  348. } catch (err) {
  349. throw err
  350. } finally {
  351. this.loading = false
  352. }
  353. },
  354. doCreate (values) {
  355. const { name, description, template, driver, target_domain, project_domain, auto_create_user, ...rest } = values
  356. const data = {
  357. name,
  358. description,
  359. driver: driver.toLowerCase(),
  360. target_domain: this.isDomainMode ? this.projectDomainId : target_domain,
  361. owner_domain_id: this.isDomainMode ? this.projectDomainId : project_domain,
  362. auto_create_user,
  363. config: {
  364. [driver.toLowerCase()]: rest,
  365. },
  366. }
  367. // 如果是cas类型,则不传递template参数
  368. if (!this.isCommon) {
  369. data.template = template
  370. }
  371. return this.manager.create({ data })
  372. },
  373. doUpdate (values) {
  374. const { driver, ...rest } = values
  375. return this.manager.performAction({
  376. id: this.id,
  377. action: 'config',
  378. data: {
  379. action: 'update',
  380. config: {
  381. [driver]: {
  382. ...rest,
  383. },
  384. },
  385. },
  386. })
  387. },
  388. async getValues () {
  389. try {
  390. const values = await this.form.fc.validateFields()
  391. const { template } = values
  392. if (template === 'qywechat_oauth2') {
  393. const { corp_id, agent_id } = values
  394. values.app_id = `${corp_id}/${agent_id}`
  395. delete values.corp_id
  396. delete values.agent_id
  397. }
  398. return values
  399. } catch (err) {
  400. throw err
  401. }
  402. },
  403. async handleSubmit () {
  404. this.submiting = true
  405. try {
  406. const values = await this.getValues()
  407. if (this.isUpdate) {
  408. await this.doUpdate(values)
  409. this.$store.commit('keepAlive/ADD_DELAY_EVENT', { name: 'ResourceListSingleRefresh', params: this.id })
  410. } else {
  411. await this.doCreate(values)
  412. }
  413. this.handleCancel()
  414. } catch (error) {
  415. throw error
  416. } finally {
  417. this.submiting = false
  418. }
  419. },
  420. handleCancel () {
  421. this.jumpTo('@idp')
  422. },
  423. driverChange (driver = 'LDAP') {
  424. const { fc } = this.form
  425. if (driver === 'LDAP') {
  426. fc.getFieldDecorator('auto_create_user', { preserve: true, valuePropName: 'checked' })
  427. }
  428. fc.setFieldsValue({
  429. template: this.templateOptions[driver][0].key,
  430. auto_create_user: driver === 'LDAP',
  431. })
  432. },
  433. async handleTemplateChange ({ target: { value } }) {
  434. const { fc } = this.form
  435. const values = fc.getFieldsValue(['driver', 'name', 'domain_id', 'auto_create_user', 'target_domain', 'project_domain'])
  436. fc.resetFields()
  437. this.form.fd = {}
  438. await this.$nextTick()
  439. values.template = value
  440. fc.setFieldsValue(values)
  441. },
  442. },
  443. }
  444. </script>