超级无敌的奇葩且复杂的需求,在朋友和我的努力下终于解决了
ps: 朋友给我写的demo,我负责cv github.com/OBQun/vue-p…
- 后端返回了部门数据,人员列表需根据最后一级获取
- 我需要把对应的人员跟部门组装成tree格式
- 支持多选,回显,人员搜索
- el-select下拉框不展示
- 回显的时候后端只返回了人员id
- 已经忘记还有什么了,太难了记不住,找朋友售后了N多次才能实现这么完美的需求
人员组件 UserPanel
<el-select
class="filter-select"
:value="value"
remote
:remote-method="getPersonList"
filterable
:loading="loading"
@change="handleSelectChange"
v-bind="$attrs"
v-on="$listeners"
:multiple="multiple"
@blur="handleSelectBlur"
@focus="popoverShow = false"
:popper-class="selectQuery ? '' : 'hide-select-popper'"
>
<el-option
v-for="person in personList"
:key="person.userId"
:value="person.userId"
:label="person.nickName"
></el-option>
</el-select>
<el-popover
v-model="popoverShow"
trigger="click"
placement="bottom"
popper-class="person-select-popover"
>
<el-cascader-panel
:value="multiple ? value : null"
:props="props"
@change="handleCascaderChange"
@expand-change="syncCascaderCheckState"
ref="cascader"
></el-cascader-panel>
<template #reference>
<i class="el-icon-user-solid person-select-suffix"></i>
</template>
</el-popover>
export default {
model: {
event: "change",
prop: "value",
},
props: {
value: {
type: [String, Array, Number],
},
multiple: Boolean,
},
data() {
return {
selectQuery: "",
popoverShow: false,
loading: false,
personList: [],
props: {
lazy: true,
value: "id",
emitPath: false,
lazyLoad: ({ root, data }, resolve) => { //组装tree结构
if (root) { // 判断是否是一级,如果是直接返回
treeselect().then(response => { // treeselect部门接口
resolve(response.data);
})
} else if (data.children) {
resolve(null);
} else { // 不是一级并且没有children,请求人员列表
listUser({ deptId: data.id }).then((res) => {
resolve(
res.rows.map(item => ({
label: item.nickName,
id: item.userId,
leaf: true
})) // 替换成自己想要的key,value
)
this.syncCascaderCheckState();
})
}
},
},
};
},
methods: {
syncCascaderCheckState() {
if (this.multiple) {
this.$refs.cascader.syncMultiCheckState();
}
},
handleSelectBlur() {
if (this.multiple) {
this.personList = this.personList.filter(({ userId }) =>
this.value.includes(userId)
);
}
},
handleSelectChange(value) {
this.$emit("change", value);
this.selectQuery = "";
this.personList = this.getSelectedOptionsByValue(value);
},
getSelectedOptionsByValue(value) {
return this.multiple
? this.personList.filter(({ userId }) => value.includes(userId))
: [this.personList.find(({ userId }) => userId === value)].filter(
Boolean
);
},
handleCascaderChange(value) {
const { cascader } = this.$refs;
if (this.multiple) {
cascader.getCheckedNodes(true).forEach(({ data: { id, label } }) => {
if (this.personList.findIndex(({ userId }) => userId === id) === -1) {
this.personList.push({ nickName: label, userId: id });
}
});
this.$emit("change", [...new Set(value.concat(this.value))]);
} else {
this.popoverShow = false;
if (value) {
this.$emit("change", value);
const [
{
data: { id, label },
},
] = cascader.getCheckedNodes();
this.personList = [{ nickName: label, userId: id }];
}
cascader.clearCheckedNodes();
cascader.activePath = [];
cascader.menus = cascader.menus.slice(0, 1);
}
},
getPersonList(query) {
this.selectQuery = query;
if(!query) return
this.loading = true;
listUser({ nickName: query })
.then(({rows}) => {
this.personList = this.multiple
? rows.concat(
this.personList.filter(
({ userId }) =>
this.value.includes(userId) &&
!~rows.findIndex(({ userId }) => this.value.includes(userId))
)
)
: rows;
})
.finally(() => {
this.loading = false;
});
},
initPersonList() {
if (this.value) {
this.loading = true;
listUser()
.then(({rows}) => {
this.personList = this.multiple
? rows.filter(({ userId }) => this.value.includes(userId))
: [rows.find(({ userId }) => userId === this.value)];
})
.finally(() => {
this.loading = false;
});
}
},
},
watch: {
multiple: {
handler(val) {
this.props.multiple = val;
},
immediate: true,
},
},
created() {
this.initPersonList();
},
};
// 使用,去掉multiple属性只能单选
user-panel-component v-model="form.bpId" clearable :multiple="isCss"></user-panel-component>