<template> <IBox :title="title" :type="type" class="the-box" v-bind="$attrs"> <table class="CardTable" style="width: 100%;table-layout:fixed;"> <tr> <td colspan="2"> <Select2 ref="select2" v-model="select2.value" :disabled="iDisabled" show-select-all v-bind="select2" /> </td> </tr> <slot /> <tr> <td colspan="2"> <el-button :disabled="iDisabled" :loading="submitLoading" :type="type" size="small" @click="addObjects"> {{ $t('Add') }} </el-button> </td> </tr> <template v-if="showHasObjects"> <tr v-for="obj of iHasObjects" :key="obj.value" class="item"> <td style="width: 100%;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;"> <el-tooltip :content="obj.label.toString()" :open-delay="500" effect="dark" placement="left" style="margin: 4px;" > <b>{{ obj.label }}</b> </el-tooltip> </td> <td> <el-button :disabled="iDisabled" size="mini" style="float: right" type="danger" @click="removeObject(obj)"> <i class="fa fa-minus" /> </el-button> </td> </tr> </template> <tr v-if="params.hasMore && showHasMore" class="item"> <td colspan="2"> <el-button :disabled="iDisabled" :type="type" size="small" style="width: 100%" @click="loadMore"> <i class="fa fa-arrow-down" /> {{ $t('More') }} </el-button> </td> </tr> </table> </IBox> </template> <script> import { createSourceIdCache } from '@/api/common' import { Select2 } from '@/components/Form/FormFields' import IBox from '@/components/IBox/index.vue' import { mapGetters } from 'vuex' export default { name: 'RelationCard', components: { Select2, IBox }, props: { title: { type: String, default: '' }, icon: { type: String, default: '' }, type: { type: String, default: 'primary' }, // 地址,发送给select2的,查询所有的objects, 和select2 ajax一样 objectsAjax: { type: Object, default: () => ({}) }, objects: { type: [Array, null], default: null }, // 已选择的objects Id, 会转换成select2的value, 作为默认选择项, 和objectsAjax类似 hasObjectsId: { type: Array, default: () => [] }, hasObjects: { type: Array, default: () => [] }, showHasObjects: { type: Boolean, default: true }, value: { type: [Array, Number, String], default: () => [] }, disabled: { type: [Boolean, Function], default: null }, showHasMore: { type: Boolean, default: true }, performDelete: { type: Function, default: (obj, that) => { } }, allowCreate: { type: Boolean, default: false }, select2Config: { type: Object, default: () => { } }, onDeleteSuccess: { type: Function, default(obj, that) { // 从 hasObjects 中移除这个object const theRemoveIndex = that.iHasObjects.findIndex((v) => v.value === obj.value) that.iHasObjects.splice(theRemoveIndex, 1) // 从 disabled values 中移除这个 value while (that.select2.disabledValues.indexOf(obj.value) !== -1) { const i = that.select2.disabledValues.indexOf(obj.value) that.$log.debug('disabled values remove index: ', i) that.select2.disabledValues.splice(i, 1) } that.$message.success(that.$t('RemoveSuccessMsg')) } }, onDeleteFail: { type: Function, default(error, that) { let msg = '' const data = error.response.data for (const item of Object.keys(data)) { const value = data[item] if (value instanceof Array) { msg = value.join(',') } else { msg = value } } that.$message.error(msg) } }, performAdd: { type: Function, default: (objects, that) => { } }, showAddAll: { type: Boolean, default: false }, onAddSuccess: { type: Function, default(objects, that) { that.$log.debug('Select value', that.select2.value) const oldValues = that.iHasObjects.map(item => item.value) that.iHasObjects = [...that.iHasObjects, ...objects.filter(item => !oldValues.includes(item.value))] that.$refs.select2.clearSelected() that.$message.success(that.$t('AddSuccessMsg')) this.$refs.select2.refresh() this.$emit('addSuccess') } }, getHasObjects: { type: Function, default: null // (objectIds) => {} } }, data() { return { iHasObjects: this.hasObjects || [], totalHasObjectsLength: 0, submitLoading: false, selectAllDisabled: false, params: { page: 1, hasMore: false, pageSize: 10 }, select2: { ajax: this.objectsAjax, options: this.objects, value: this.value, disabled: this.disabled, disabledValues: [], allowCreate: this.allowCreate, ...this.select2Config } } }, computed: { ...mapGetters(['currentOrgIsRoot']), iAjax() { return this.$refs.select2.iAjax }, safeMakeParams() { return this.$refs.select2.safeMakeParams }, hasObjectLeftLength() { return this.totalHasObjectsLength - this.iHasObjects.length }, iDisabled() { if (this.disabled !== null) { return this.disabled } return this.currentOrgIsRoot } }, watch: { hasObjectsId(iNew, iOld) { this.$log.debug('hasObject id change') this.select2.disabledValues = iNew }, iHasObjects(iNew, iOld) { const newValues = iNew.map(v => v.value) const oldValues = iOld.map(v => v.value) const addValues = _.difference(newValues, oldValues) const removeValues = _.difference(oldValues, newValues) this.$log.debug('hasObjects change, add ', addValues, 'remove ', removeValues) let disabledValues = this.select2.disabledValues if (removeValues.length > 0) { disabledValues = disabledValues.filter((v) => { return removeValues.indexOf(v) === -1 }) } if (addValues.length > 0) { disabledValues = [...disabledValues, ...addValues] } this.select2.disabledValues = disabledValues } }, mounted() { if (this.hasObjectsId && this.hasObjectsId.length !== 0) { setTimeout(() => { this.getHasObjectsByIds() }, 50) } }, methods: { async loadMore() { if (this.loading) { return } if (!this.params.hasMore) { return } this.params.page = this.params.page ? this.params.page + 1 : 1 try { this.loading = true await this.loadHasObjects() } finally { this.loading = false } }, async loadHasObjects() { this.$log.debug('Start loadHasObject: ', this.params) const params = this.safeMakeParams(this.params) let data = await this.$axios.get(this.iAjax.url, { params: params, validateStatus: (status) => { if (status === 403) { return 200 } return status } }) data = this.iAjax.processResults.bind(this)(data) if (data.results) { data.results.forEach((v) => { if (!this.iHasObjects.find((item) => item.value === v.value)) { this.iHasObjects.push(v) } }) } // 如果还有其它页,继续获取, 如果没有就停止 this.params.hasMore = !!data.pagination this.totalHasObjectsLength = data.total }, async getHasObjectsByIds() { if (!this.$refs.select2 || !this.iAjax || !this.safeMakeParams) { return } this.select2.disabledValues = this.hasObjectsId if (this.getHasObjects) { this.getHasObjects(this.hasObjectsId).then((data) => { this.iHasObjects = data }) } else { const resp = await createSourceIdCache(this.hasObjectsId) this.params.spm = resp.spm await this.loadHasObjects() } }, removeObject(obj) { this.performDelete(obj, this).then(() => { this.onDeleteSuccess(obj, this) }).catch(error => { this.onDeleteFail(error, this) }) }, addObjects() { const objects = this.$refs.select2.$refs.select.selected.map(item => ({ label: item.label, value: item.value })) if (objects.length === 0) { return } this.performAdd(objects, this).then( () => { this.onAddSuccess(objects, this) } ) }, async selectAll() { this.selectAllDisabled = true this.disabled = true await this.$refs.select2.selectAll() this.selectAllDisabled = false this.disabled = false } } } </script> <style lang='scss' scoped> b, strong { font-weight: 700; font-size: 13px; } tr td { line-height: 1.4; padding: 8px 0; vertical-align: top; } tr.item td { border-top: 1px dashed #EBEEF5; } .box-margin { margin-bottom: 20px; } .the-box ::v-deep .el-card__body { padding: 20px; } </style>