• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

我的博客我做主

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

列表的批量操作组件封装 + 权限 ,如何更优雅的实现呢?Vue3

  1. 这个组件解决的问题?

    在以往的项目当中,我从未想过要对 批量/列表数据的操作按钮做什么变动,直到最近的一次开发。
    当页面功能多而复杂,整个页面会变得十分混乱,就比如,当操作按钮过多时,操作按钮的触发判断条件、权限指令、更多下拉操作等等,这使得页面十分混乱,维护起来让人头疼。
    当然也会出现:多个操作弹窗、搜索条件过多、监听路由参数变化。我会在后面的随笔中记录。

  2. 当操作按钮过多时,如何解决这个问题

    封装批量操作组件,操作按钮分明显按钮 和 更多下拉操作按钮。
    将页面操作放在action.js 文件中,包含 触发判断条件、权限指令、控制显示/隐藏。

  3. 如何使用?

    全局(main.js中)引用操作组件 BatchOperation.vue
    创建页面操作按钮 actions.js 文件

  4. BatchOperation.vue 全局操作按钮组件文件代码:

    <template>
       <div>
       <!-- 列表顶部的批量操作按钮组件  / 表格中的操作按钮-->
           <el-row :gutter="10" class="mb8 mt10" type="flex" justify="center">
               <slot name="default"></slot>
               <el-col :span="1.5" v-for="action, index in visibleAction" :key="action.command" v-show="visibleAction.length > 0">
                   <el-button :link="inColumn" :type="getBtnType(index)" plain :disabled="action.disabled" v-hasPermi="action.permission" @click="commandAction(action.command)">{{action.name}}</el-button>
               </el-col>
               <el-col :span="1.5" v-if="moreActionsVisible">
                   <el-dropdown @command="commandAction" :size="inColumn ? 'default' : 'large'" style="line-height:inherit;vertical-align: bottom;">
                       <el-button type="primary" plain :link="inColumn">
                           更多操作<el-icon class="el-icon--right"><arrow-down /></el-icon>
                       </el-button>
                       <template #dropdown>
                           <el-dropdown-menu>
                               <div v-hasPermi="action.permission" v-for="action in moreActions" :key="action.command">
                                   <el-dropdown-item :disabled="action.disabled" :command="action.command" >
                                       {{action.name}}
                                   </el-dropdown-item>
                               </div>
                           </el-dropdown-menu>
                       </template>
                   </el-dropdown>
               </el-col>
               <slot name="rightToolbar"></slot>
           </el-row>
       </div>
    </template>
    <script setup>
    import take from 'lodash/take'
    import takeRight from 'lodash/takeRight'
    import mapValues from 'lodash/mapValues'
    import pickBy from 'lodash/pickBy'
    import values from 'lodash/values'
    import sortBy from 'lodash/sortBy'
    // button type
    const btnType = ['primary', 'success', 'warning', 'danger', 'info', 'default']
    // props
    const getBtnType =(index)=>{
       const indx = index % btnType.length
       return btnType[indx]
    }
    // actions command
    const emits = defineEmits()
    // props
    const props = defineProps(['actions','visibleCount','inColumn'])
    // 明显按钮 默认显示前五个按钮; 如果是在 数据行操作只显示 1 个
    const MAX = computed(()=>{
       const count = props.inColumn ? 1 : 5
       return props.visibleCount === undefined ? count : props.visibleCount
    })
    // 将 key 作为 command。 hiddenInColunm 在表中隐藏 onlyInColunm 只在表格列中显示 hidden 都不显示
    const operations = computed(()=>{
       let actions = pickBy(props.actions, a =>(props.inColumn ? (!a.hiddenInColunm) : !a.onlyInColunm) && !a.hidden)
       actions = mapValues(actions,(value,key)=>{
           value.command = key
           return value
       })
       // 将可用功能优先排序
      return sortBy(values(actions), (a)=>a.disabled)
    })
    // 明显按钮
    const visibleAction = computed(()=>{
       return take(operations.value, MAX.value)
    })
    // 更多操作下拉按钮
    const moreActions = computed(()=>{
       return takeRight(operations.value, operations.value.length - MAX.value)
    })
    // 是否显示更多按钮
    const moreActionsVisible = computed(()=>MAX.value == 0 || operations.value.length > visibleAction.value.length)
    // 点击更多操作里的按钮
    const commandAction =(command)=>{
       emits(command)
    }
    </script>
    
  5. actions.js 页面操作,举个例子:

    // single:批量勾选 false 单条数据,true 非单条数据
    // multiple:批量勾选 false 已勾选 true 未勾选
    // row:单行数据。当 single 为 false 时, row 也须有值 
    export default function (single, multiple, row) { 
         return {
             'create': {
                 name: "新增",// 按钮名称
                 permission: ['bless:product:permissionAdd'],// 权限字符
                 disabled: false, // 是否可点击
                 hiddenInColunm: true // 在表格列中隐藏
             },
             'edit': {
                 name: "修改",
                 permission: ['bless:product:permissionEdit'],
                 // 单行 或者 row 存在且符合( ... )中的条件时
                 disabled: single || ( row ? ( row.status !=0 && row.status !=3 ) : true),
                 onlyInColunm: true // 仅在列表中显示
             },
             'delete': {
                 name: "删除",
                 permission: ['bless:product:permissionRemove'],
                 disabled: multiple,
             },
             'search': {
                 name: "查询", 
                 permission: ['bless:product:permissionPage'],
                 disabled: false,
                 hidden: true // 隐藏
             }
         }
     }
    
  6. 页面使用操作按钮:UI 组件:element-plus

      <template>
         <!-- v-hasPermi 权限指令 详见 若依--自定义指令-->
         <div v-hasPermi="actions['search'].permission">
             <!-- 批量操作 -->
             <BatchOperation 
                :actions="actions" 
                @create="handleCreate"
                @delete="handleDelete"
                >
                 <!-- 刷新按钮 -->
                 <template #rightToolbar>
                     <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
                 </template>
             </BatchOperation>
             <!-- 列表 -->
             <el-table :data="list" row-key="productId" @selection-change="handleSelectionChange">
                <!-- 勾选框 -->
                <el-table-column type="selection" width="55" align="center" fixed="left" />
                ...(这里就是列表展示的数据)
                <!-- 单行操作按钮 -->
                <el-table-column label="操作" fixed="right" header-align="center" width="150px">
                      <template #default="{row}">
                         <BatchOperation 
                         :inColumn="true"
                         :actions="initAction(false, false, row)"
                         @edit="handleEdit(row)"
                         @delete="handleDelete(row.productId)"
                         ></BatchOperation>
                      </template>
                </el-table-column>
             </el-table>
         </div>
      </template>
      <script setup name="ProductIndex">
         import { getPages, remove } from '@/api/product'
         import initAction from './components/actions'
         // 勾选
         const multipleSelection = ref([]) // ids
         // 非单个禁用
         const single = computed(() => multipleSelection.value.length != 1)
         // 非多个禁用
         const multiple = computed(() => !multipleSelection.value.length)
         // 当前选中
         const selectedRow = computed(() => {
            if (multipleSelection.value.length == 1) {
                  return list.value.find(z => z.productId == multipleSelection.value[0])
            }
            return null
         })
         // 批量操作按钮
         const actions = computed(()=>initAction(single.value, multiple.value, selectedRow.value))
         // 批量勾选触发
         const handleSelectionChange = (val) => {
            multipleSelection.value = val.map(z => z.productId)
         }
         // 点击 新增
           const handleCreate =()=>{
               router.push('/product/create')
           }
         // 点击 修改
         const handleEdit =(row)=>{
            const current = row || selectedRow.value
            router.push('/product/edit/' + current.productId)
         }
         // 批量删除
         const handleDelete = (id) => {
            proxy.$modal.confirm('确定删除?')
               .then(() => {
                  const ids = id || multipleSelection.value
                  remove(ids).then(res => {
                     if (res.code == 200) {
                           proxy.$modal.msgSuccess("操作成功")
                           getList()
                     } else {
                           proxy.$modal.msgError(res.msg || "请求发生错误,请稍后重试")
                     }
                  })
               })
               .catch(() => {
                  proxy.$modal.msg("已取消")
               })
         }
         // 获取列表数据
         const getList = () => {
            proxy.$modal.loading("加载中...")
            // **这里 searchRef 会在后面的随笔中说明**
            const { dateRange, ...search } = searchRef.value.form
            const query = { ...pager.value, ...search }
            const data = dateRange ? proxy.addDateRange(query, dateRange) : query
            getPages(data).then(response => {
                  list.value = response.data.rows;
                  total.value = parseInt(response.data.total);
                  expandRowKeys.value = []
            }).finally(() => {
                  proxy.$modal.closeLoading();
            });
         }
      </script>
作者:胡倩倩0903
出处:https://www.cnblogs.com/kitty-blog/
本文版权归作者和博客园共有,欢迎转载,但必须给出原文链接,并保留此段声明,否则保留追究法律责任的权利。

posted on 2023-05-08 09:27  kitty20180903suzhou  阅读(236)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3