| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225 |
- <!-- 部门树形选择下拉框 -->
- <template>
- <ele-tree-select
- clearable
- :value="value || ''"
- :data="treeData"
- label-key="name"
- value-key="id"
- default-expand-all
- :placeholder="placeholder"
- :filterable="filterable"
- :filter-method="deptFilterMethod"
- @input="updateValue"
- @change="changeChoose"
- @visible-change="visibleChange"
- ref="treeSelect"
- v-bind="$attrs"
- />
- </template>
- <script>
- import { listOrganizations } from '@/api/system/organization';
- import { getCurrentUser } from '@/utils/token-util';
- export default {
- props: {
- // 选中的数据(v-model)
- value: [Number, String],
- // 提示信息
- placeholder: {
- type: String,
- default: '请选择'
- },
- // 是否在下拉框内显示搜索框
- filterable: {
- type: Boolean,
- default: false
- },
- // 是否只显示当前登录用户所属公司的机构
- companyScope: {
- type: Boolean,
- default: false
- },
- // 自定义搜索过滤方法(关键字, 节点数据),不传则默认按部门名称/部门编码匹配
- filterMethod: {
- type: Function,
- default: null
- }
- },
- data() {
- return {
- treeData: []
- };
- },
- computed: {
- // 传给 ele-tree-select 的过滤方法
- deptFilterMethod() {
- return this.filterMethod || this.defaultFilterMethod;
- }
- },
- created() {
- this.getData();
- },
- methods: {
- // 默认过滤:按部门名称或部门编码模糊匹配(不区分大小写)
- defaultFilterMethod(keyword, data) {
- const key = (keyword || '').trim().toLowerCase();
- if (!key) {
- return true;
- }
- return (
- (data.name || '').toLowerCase().includes(key) ||
- (data.groupCode || '').toLowerCase().includes(key)
- );
- },
- async getData(parmas = {}) {
- const data = await listOrganizations(parmas);
- const list = this.companyScope
- ? this.filterByCurrentCompany(data || [])
- : data || [];
- this.treeData = this.$util.toTreeData({
- data: list,
- idField: 'id',
- parentIdField: 'parentId'
- });
- },
- /* 当前登录用户所属机构id(优先取顶栏切换后的当前机构) */
- getCurrentGroupId() {
- let currentGroupId = null;
- try {
- currentGroupId = getCurrentUser()?.currentGroupId;
- } catch (e) {
- currentGroupId = null;
- }
- const userInfo = this.$store?.state?.user?.info || {};
- return currentGroupId || userInfo.groupId || null;
- },
- /* 只保留当前登录用户所属公司(顶级机构)下的机构 */
- filterByCurrentCompany(list) {
- const groupId = this.getCurrentGroupId();
- if (groupId == null || groupId === '') {
- return list;
- }
- const nodeMap = new Map();
- list.forEach((item) => nodeMap.set(String(item.id), item));
- if (!nodeMap.has(String(groupId))) {
- // 找不到当前用户所属机构时不做过滤, 避免下拉框被清空
- return list;
- }
- const companyCache = new Map();
- /* 沿 parentId 上溯, 取所属顶级机构(公司) */
- const getCompanyId = (id) => {
- const key = String(id);
- if (companyCache.has(key)) {
- return companyCache.get(key);
- }
- let node = nodeMap.get(key);
- let companyId = key;
- const visited = new Set();
- while (node) {
- companyId = String(node.id);
- const parentKey =
- node.parentId == null || node.parentId === ''
- ? ''
- : String(node.parentId);
- if (
- !parentKey ||
- !nodeMap.has(parentKey) ||
- visited.has(companyId)
- ) {
- break;
- }
- visited.add(companyId);
- node = nodeMap.get(parentKey);
- }
- companyCache.set(key, companyId);
- return companyId;
- };
- const companyId = getCompanyId(groupId);
- const selectedKey =
- this.value == null || this.value === '' ? '' : String(this.value);
- const selectedCompanyId =
- selectedKey && nodeMap.has(selectedKey)
- ? getCompanyId(selectedKey)
- : '';
- return list.filter((item) => {
- const itemCompanyId = getCompanyId(item.id);
- if (itemCompanyId === companyId) {
- return true;
- }
- // 已选机构属于其他公司时一并保留, 保证编辑/详情能正常回显名称
- return !!selectedCompanyId && itemCompanyId === selectedCompanyId;
- });
- },
- /* 更新选中数据 */
- updateValue(value) {
- this.$emit('input', value);
- },
- changeChoose(val) {
- this.$emit(
- 'changeGroup',
- val,
- this.$refs.treeSelect.getNodeByValue(val)
- );
- },
- // 下拉框展开/收起时清空上一次的搜索关键字,保证每次打开都是空的
- visibleChange() {
- this.$nextTick(() => {
- const treeSelect = this.$refs.treeSelect;
- if (treeSelect && treeSelect.keywords) {
- treeSelect.keywords = '';
- treeSelect.filterNode();
- }
- });
- },
- async locateByName(code) {
- await this.getData();
- const res = this.findNodesByNameWithPath(this.treeData, code);
- console.log(res);
- if (!res.length) return;
- const { node, path } = res[0];
- this.$nextTick(() => {
- // 设置选中
- this.updateValue(node.id);
- this.changeChoose(node.id);
- // 展开树路径
- const tree = this.$refs.treeSelect?.$refs?.tree;
- if (!tree) return;
- path.forEach((p) => {
- const treeNode = tree.store.nodesMap[p.id];
- treeNode && treeNode.expand();
- });
- });
- },
- findNodesByNameWithPath(tree, code) {
- const result = [];
- function dfs(list, path = []) {
- list.forEach((node) => {
- const currentPath = [...path, node];
- if (node.groupCode == code) {
- result.push({
- node,
- path: currentPath
- });
- }
- if (node.children?.length) {
- dfs(node.children, currentPath);
- }
- });
- }
- dfs(tree);
- return result;
- }
- }
- };
- </script>
|