[BD2.0] 树形用户列表筛选的实现(完成版)

103 阅读3分钟
菜单设置
  • 1.放在自定义用户管理下面, 然后添加给各级管理员

image.png

代码
  • 1.前端列表页面
<template>
<el-row :gutter="0">

    <el-col class="user-filter" :span="3"><div class="grid-content ep-bg-purple" />
        <el-input v-model="filterText" placeholder="Filter keyword" />
        <el-tree
            ref="treeRef"
            class="filter-tree"
            :data="list"
            :props="{children: 'children', label: 'label'}"
            default-expand-all
            :filter-node-method="filterNode"
            :expand-on-click-node="false" 
            @node-click="NodeClick"
        />
    </el-col>

    <el-col :span="21">
        <div class="default-main ba-table-box">
            <el-alert class="ba-table-alert" v-if="baTable.table.remark" :title="baTable.table.remark" type="info" show-icon />
            <TableHeader
                :buttons="['refresh', 'add', 'edit', 'delete', 'comSearch', 'quickSearch', 'columnDisplay']"
                :quick-search-placeholder="t('Quick search placeholder', { fields: t('goods.quick Search Fields') })"
            ></TableHeader>

            <Table ref="tableRef"></Table>
            <PopupForm />
        </div>
    </el-col>
</el-row>
    
</template>

<script setup lang="ts">
import { ref, provide, onMounted } from 'vue'
import baTableClass from '/@/utils/baTable'
import { defaultOptButtons } from '/@/components/table'
import { baTableApi } from '/@/api/common'
import { useI18n } from 'vue-i18n'
import PopupForm from './popupForm.vue'
import Table from '/@/components/table/index.vue'
import TableHeader from '/@/components/table/header/index.vue'
import goodsStatus from '/@/config/status/goodsStatus'

// 导入user管理的控制器Url,类似:/index.php/admin/user.user/ -- 1.0版本的文件
import { goodsCategory, userUser } from '/@/api/controllerUrls' 

defineOptions({
    name: 'goods',
})

const { t } = useI18n()
const tableRef = ref()
const optButtons: OptButton[] = defaultOptButtons(['edit', 'delete'])


const baTable = new baTableClass(
    new baTableApi('/admin/Goods/'),
    {
        pk: 'id',
        column: [
            { type: 'selection',  operator: false },
            { label: t('goods.id'), prop: 'id',  width: 70,  sortable: 'custom', operator: false},
            { label: 'category', prop: 'category_id', comSearchRender: 'remoteSelect', show:false, remote: {
                pk: 'id',
                field: 'title',
                remoteUrl: goodsCategory +'index'            
            }},
            { label: '用户', prop: 'seller_id',  show:false},
        ],
        dblClickNotEditColumn: ['all'],
    },
    {
        defaultItems: { created_at: null },
    }
)

provide('baTable', baTable)

onMounted(() => {
    baTable.table.ref = tableRef.value
    baTable.mount()
    baTable.getIndex()?.then(() => {
        baTable.initSort()
        baTable.dragSort()
    })
})
 
////////////////////////////////////// 树形筛选 //////////////////////////////////////
import { watch, reactive } from 'vue'
import { ElTree } from 'element-plus'
import { getArrayKey } from '/@/utils/common'
import { getUserTree } from '/@/api/public/member/member'

interface Tree {
  [key: string]: any
}

const filterText = ref('')
const treeRef = ref<InstanceType<typeof ElTree>>()

watch(filterText, (val) => {
  treeRef.value!.filter(val)
})

const filterNode = (value: string, data: Tree) => {
  if (!value) return true
  return data.label.includes(value)
}

const list = ref<Tree[]>([]) // 使用ref包装data

getUserTree().then((res) => {
    console.log("@@获取树形用户", res);
    list.value = res.data.list
})

// 树形用户被点击  
const NodeClick = (data: { id: any }) => {
  
    baTable.table.showComSearch = true
    baTable.comSearch.form = Object.assign(baTable.comSearch.form, {
        'seller_id': data.id
    })

    const fieldDataTemp = baTable.comSearch.fieldData.get('seller_id') 
    if (fieldDataTemp) {
        // 筛选数据组装
        let comSearchData: comSearchData = {
            field: 'seller_id', // 筛选字段
            val: data.id, // 范围查询的 start 值和 end 值,直接使用逗号分隔
            operator: fieldDataTemp.operator, // 公共搜索操作符号
            render: fieldDataTemp.render, // 字段渲染方案
        }

        let index = getArrayKey(baTable.table.filter!.search!, 'field', 'seller_id') // 查询是否已经有 id 字段的筛选数据
        if (!index) {
            // push 到要发送给服务端的筛选条件数组中
            baTable.table.filter!.search!.push(comSearchData) // 无则 push
        } else {
            baTable.table.filter!.search![index] = comSearchData // 有则重新赋值
        }
        baTable.onTableHeaderAction('refresh', {})
    } else {
        console.log('没有找到 id 字段的公共搜索数据,因为该字段禁止了公共搜索')
    }
}
</script>

<style scoped lang="scss">
.user-filter {
    margin-top: 20px;
    padding: 0 5px;
}
</style>

  • 2.封装http请求 web\src\api\public\member\member.ts,可以看到不用写batoken
import createAxios from '/@/utils/axios'

export function getUserTree() {
    return createAxios({
        url: '/admin/member/getUserTree',
        method: 'get',
    })
}
  • 3.Member控制器(没有放在公共接口控制器之类的) app\admin\controller\Member.php
<?php

namespace app\admin\controller;
use app\common\controller\Backend;

// 省略了多余代码
class Member extends Backend
{

    protected object $model;

    protected $uid = null;
    protected $child = [];

    public function initialize(): void
    {
        parent::initialize();
        $this->model = new \app\admin\model\Member;
        $this->uid = $this->auth->getAdmin()->id;
        $this->child = $this->model->getChildList($this->uid, $this->auth->isSuperAdmin()); //可见用户列表
    }

    /**
     * 前端树形用户列表筛选
     */
    public function getUserTree()
    {
        $list = $this->model->getUserTree($this->uid, $this->auth->isSuperAdmin());
        
        return $this->success('', [
            'list'   => $list, // 注意层级
            'total'  => count($list),   
        ]);

    }
}
  • 4.用户模型
<?php

namespace app\admin\model;
use think\Model;

class Member extends Model
{
    // 表名
    protected $name = 'admin';

    // 自动写入时间戳字段
    protected $autoWriteTimestamp = true;

    public function pidTable(): \think\model\relation\BelongsTo
    {
        return $this->belongsTo(\app\admin\model\Admin::class, 'pid', 'id');
    }


    /**
     * [Tree.1] 获取树形用户
     * @return array 最后返回的是用于显示前端树形用户列表筛选的数组
     * 
     * $list = [[
     *        'id'    => 2,
     *        'label' => '刘备',
     *        'children'  => [
     *            [
     *                'id'    => 3,
     *                'label' => '关羽',
     *                'children'  => [
     *                    ['id'=> 4,'label' => '关平']
     *                ]
     *            ]
     *        ]
     *    ]];
     */
    public function getUserTree($uid = 0, $isSuper = false)
    {
        if ($isSuper) {
            $res = $this->field(['id','username label','pid'])->where("pid", 0)->where('id', '<>', 1)->select()->toArray();
        } else {
            $res = $this->field(['id','username label','pid'])->where("id", $uid)->select()->toArray();
        }
        $list = [];
        foreach ($res as $item) {
            $list[] = [
                'id'    => $item['id'],
                'pid'   => $item['pid'],
                'label' => $item['label'],
            ];
        }
        foreach ($list as &$user) {
            $child = $this->getChildren($user['id']);
            $user['children'] = $child;
        }
        return $list;
    }

    /**
     * [Tree.2] 树形方法2
     * 获取指定用户的所有子用户
     */
    public function getChildren($id)
    {
        $children = $this->hidden(['group_arr'])->field(['id','username label','pid'])->where('pid', $id)->select()->toArray();
        $list = [];
        foreach ($children as $item) {
            $list[] = [
                'id'    => $item['id'],
                'pid'   => $item['pid'],
                'label' => $item['label'],
            ];
        }
        foreach ($list as &$child) {
            $child['children'] = $this->getChildren($child['id']);
        }
        return $list;
    }
    
    // 对外使用: 获取获取所有下级用户的ID数组
    public function getChildList($uid, $isSuperAdmin = false)
    {
        if ($isSuperAdmin && $uid == 1) {
            $result = $this->getAllUids();            
        } else {
            $result = $this->getChildIds($uid);
            $result[] = $uid; // 添加当前用户
        }
        return $result;
    }

    // 无限极方法,获取所有下级用户的ID数组(只供内部使用)
    private function getChildIds($uid)
    {
        $subordinateIds = [];
        $subordinates = $this->where('pid', $uid)->select();
        foreach ($subordinates as $subordinate) {
            $subordinateIds[] = $subordinate->id;
            $subordinateIds = array_merge($subordinateIds, $this->getChildIds($subordinate->id));
        }
        return $subordinateIds;
    }

    /**
     * 获取所有用户id
     * @return array 最后返回的是一维数组, 由所有用户ID组成的
     */
    private function getAllUids()
    {
        $result = $this->where('id', '<>', 1)->column('id');
        return $result;
    }
}