Vue中使用Transfer实现表格穿梭框(可搜索)

需求:使用Transfer实现带分页并可搜索的穿梭框。给不同用户分配不同的应用服务。

前端

1.注册组件(main.js)

import {  Transfer, Table, Switch } from 'ant-design-vue'
Vue.use(Transfer)
Vue.use(Table)
Vue.use(Switch)

2.Transfer中使用 Table 组件自定义渲染列表

这里用的是eladmin-ui中的el-dialog,以点击按钮的方式弹出穿梭框

2.1 自定义渲染列表
<el-dialog v-if="transferVisible" append-to-body :close-on-click-modal="false" :visible.sync="transferVisible" width="1000px" @before-close="transferClose">
  <div>
    <a-transfer
      :data-source="mockData"
      :target-keys="targetKeys"
      :show-search="true"
      :filter-option="(inputValue, item) => item.title.indexOf(inputValue) !== -1"
      :show-select-all="false"
      @change="onChange"
    >
      <template
        slot="children"
        slot-scope="{
          props: { direction, filteredItems, selectedKeys, disabled: listDisabled },
          on: { itemSelectAll, itemSelect },
        }"
      >
        <a-table
          :row-selection="
            getRowSelection({ disabled: listDisabled, selectedKeys, itemSelectAll, itemSelect })
          "
          :columns="direction === 'left' ? leftColumns : rightColumns"
          :data-source="filteredItems"
          size="small"
          :style="{ pointerEvents: listDisabled ? 'none' : null }"
          :custom-row="
            ({ key, disabled: itemDisabled }) => ({
              on: {
                click: () => {
                  if (itemDisabled || listDisabled) return;
                  itemSelect(key, !selectedKeys.includes(key));
                },
              },
            })
          "
        />
      </template>
    </a-transfer>
  </div>
  <div slot="footer">
    <el-button type="text" @click="transferClose">取消</el-button>
    <el-button type="primary" @click="transferSub">提交</el-button>
  </div>
</el-dialog>
2.2 定义变量
const mockData = []
const originTargetKeys = []
const leftTableColumns = [
  {
    dataIndex: 'title',
    title: '应用名称'
  },
  {
    dataIndex: 'description',
    title: '服务名称'
  }
]
const rightTableColumns = [
  {
    dataIndex: 'title',
    title: '应用名称'
  }
]
data(){
	return {
      transferVisible: false,
      mockData,
      targetKeys: originTargetKeys,
      disabled: false,
      showSearch: false,
      leftColumns: leftTableColumns,
      rightColumns: rightTableColumns,
}
2.3 回调函数
onChange(nextTargetKeys) {
  this.targetKeys = nextTargetKeys
},
getRowSelection({ disabled, selectedKeys, itemSelectAll, itemSelect }) {
  return {
    getCheckboxProps: item => ({ props: { disabled: disabled || item.disabled }}),
    onSelectAll(selected, selectedRows) {
      const treeSelectedKeys = selectedRows
        .filter(item => !item.disabled)
        .map(({ key }) => key)
      const diffKeys = selected
        ? difference(treeSelectedKeys, selectedKeys)
        : difference(selectedKeys, treeSelectedKeys)
      itemSelectAll(diffKeys, selected)
    },
    onSelect({ key }, selected) {
      itemSelect(key, selected)
    },
    selectedRowKeys: selectedKeys
  }
}

3.加载渲染数据

3.1 渲染mockData(左边数据)

这里页面加载就获取全部数据并渲染mockData

created() {
	this.initAppData()
},
methods: {
   initAppData() {
     getAppAll().then(res => {
       if (res.data && res.data.length > 0) {
         this.mockData = res.data.map(item => {
           return {
             key: item.appid,
             title: item.appName || '暂无',
             description: item.serviceName || '暂无',
             disabled: false
           }
         })
       }
     }).catch(() => { })
   }
}

这里getAppAll()的后台接口就不贴出来了,就是简单地获取List。

3.2 加载用户数据(右边数据)

queryListByUserId:根据不同的用户Id获取对应的应用List<Id>;后台实现见下面后端代码。

// 分配App
allot(rowData) {
 this.transferVisible = true
 this.userId = rowData.id
 queryListByUserId({ userId: rowData.id }).then(response => {
   mockData.filter(item => response.indexOf(item.key) > 0).map(item => item.key)
   this.targetKeys = response
 }).catch(() => { })
},
// 关闭穿梭框
transferClose() {
 this.transferVisible = false
}

后端

1.关联表

建立用户和应用的关联表
在这里插入图片描述

2.查询关联数据

自己实现对应的查询逻辑,这里只贴Service代码

/**
 * 根据用户ID查询App信息
 * @param userId
 * @return
 */
List<String> queryListByUserId(String userId);

3.提交绑定

前端提交按钮事件:

transferSub() {
 addUserApps({ userId: this.userId.toString(), appIds: this.targetKeys }).then(res => {
   this.$notify({
     title: '提交成功',
     type: 'success',
     duration: 2500
   })
   this.transferVisible = false
 }).catch((err) => {
   this.$notify({
     title: '提交失败' + err,
     type: 'error',
     duration: 2500
   })
 })
}

后端提交逻辑(因本人比较懒,采用的是先删除再添加的懒人方法)

public Result addUserApps(@RequestBody UsersAppsVo usersAppsVo){
   // 先删除
   usersAppsService.delAppsByUserId(usersAppsVo.getUserId());
   // 再插入
   usersAppsService.addUserApps(usersAppsVo.getAppIds(),usersAppsVo.getUserId());
   return  Result.ok();
}

效果图:
在这里插入图片描述

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐