123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255 |
- <template>
- <div
- class="property-tree-select el-select el-select--small"
- @click="switchOpen"
- >
- <div
- :class="[
- 'el-input el-input--small el-input--suffix',
- { 'is-focus': isFocus, 'is-disabled': disabled },
- ]"
- @mouseenter="inputHovering = true"
- @mouseleave="inputHovering = false"
- >
- <input
- ref="inputRef"
- type="text"
- autocomplete="off"
- :placeholder="placeholder"
- class="el-input__inner"
- :value="selectedPropName"
- readonly
- :disabled="disabled"
- />
- <span class="el-input__suffix">
- <span class="el-input__suffix-inner">
- <i
- v-show="!showClose"
- :class="[
- 'el-select__caret',
- 'el-input__icon',
- 'el-icon-arrow-up',
- { 'is-reverse': visible },
- ]"
- ></i>
- <i
- v-if="showClose && !disabled"
- class="el-select__caret el-input__icon el-icon-circle-close"
- @click="handleClearClick"
- ></i>
- </span>
- </span>
- </div>
- <el-popover
- v-model="visible"
- popper-class="property-popover"
- placement="bottom-left"
- trigger="manual"
- >
- <div ref="popoverRef" slot="reference"></div>
- <div v-clickoutside="handleClose" class="property-popover-tree">
- <el-tree
- ref="PropertyTree"
- :data="proptree"
- default-expand-all
- show-checkbox
- node-key="id"
- :props="defaultProps"
- :check-strictly="true"
- check-on-click-node
- :expand-on-click-node="false"
- @check-change="checkChange"
- @check="handleCheck"
- >
- <span slot-scope="{ data }" :class="['custom-tree-node']">
- <span v-if="!data.code">{{ data.name }}</span>
- <span v-else>[{{ data.code }}]{{ data.name }}</span>
- </span>
- </el-tree>
- </div>
- </el-popover>
- </div>
- </template>
- <script>
- import { propertyTreeQueryApi, propertyNameQueryApi } from "../api";
- import Clickoutside from "element-ui/src/utils/clickoutside";
- export default {
- name: "PropertyTreeSelect",
- directives: { Clickoutside },
- props: {
- value: {
- type: [Array, String],
- default: "",
- },
- placeholder: { type: String, default: "请选择" },
- multiple: {
- type: Boolean,
- default: false,
- },
- disabled: {
- type: Boolean,
- default: false,
- },
- clearable: {
- type: Boolean,
- default: true,
- },
- courseId: {
- type: [String, Number],
- default: "",
- },
- },
- data() {
- return {
- selectedPropName: "",
- selectedPropList: [],
- selectedPropIds: [],
- visible: false,
- isFocus: false,
- inputHovering: false,
- proptree: [],
- defaultProps: {
- children: "propertyList",
- disabled: "disabled",
- },
- };
- },
- computed: {
- showClose() {
- let hasValue = this.multiple
- ? Array.isArray(this.value) && this.value.length > 0
- : this.value !== undefined && this.value !== null && this.value !== "";
- let criteria = this.clearable && this.inputHovering && hasValue;
- return criteria;
- },
- },
- watch: {
- value(val, oldval) {
- if (val !== oldval) this.initSelected(val);
- },
- courseId(val, oldval) {
- // console.log(val, oldval);
- if (val !== oldval) {
- this.resetData();
- this.emitChange();
- this.getList();
- }
- },
- },
- mounted() {
- this.getList();
- },
- methods: {
- resetData() {
- this.$refs.PropertyTree.setCheckedKeys([]);
- this.selectedPropName = "";
- this.selectedPropList = [];
- this.selectedPropIds = [];
- this.visible = false;
- this.isFocus = false;
- this.inputHovering = false;
- this.proptree = [];
- },
- async getList() {
- if (!this.courseId) return;
- const res = await propertyNameQueryApi(this.courseId);
- let propList = res.data || [];
- const fetchAll = propList.map((item) => propertyTreeQueryApi(item.id));
- const datas = await Promise.all(fetchAll).catch(() => {});
- if (!datas) return;
- this.proptree = propList.map((item, index) => {
- let nitem = { ...item, disabled: true, isCourseProperty: true };
- nitem.propertyList = datas[index].data;
- return nitem;
- });
- if (this.value) this.initSelected(this.value);
- },
- switchOpen() {
- if (this.disabled) return;
- if (this.visible) {
- this.handleClose();
- } else {
- this.handleOpen();
- }
- },
- handleOpen() {
- this.isFocus = true;
- setTimeout(() => {
- this.visible = true;
- }, 100);
- },
- handleClose() {
- this.visible = false;
- this.isFocus = false;
- },
- initSelected(val) {
- this.$refs.PropertyTree.setCheckedKeys(val);
- },
- handleClearClick(event) {
- event.stopPropagation();
- this.$refs.PropertyTree.setCheckedKeys([]);
- this.selectedPropName = "";
- this.emitChange();
- this.handleClose();
- },
- checkChange() {
- const nodes = this.$refs.PropertyTree.getCheckedNodes();
- this.selectedPropName = nodes.map((item) => item.name).join(";");
- this.emitChange();
- },
- handleCheck(nodeObj, tree) {
- let checkedCount = tree.checkedNodes.length;
- if (checkedCount > 3) {
- // 如果超出限制,则取消最后一次勾选
- this.$refs.PropertyTree.setChecked(nodeObj.id, false);
- this.$message.error("最多只能选择3个");
- }
- },
- getCheckedPropertyInfos(selectedPropIds = []) {
- let propertyInfos = [];
- const getProperty = (propertyList, parents) => {
- propertyList.forEach((item) => {
- let nitem = Object.assign({}, item, { propertyList: null });
- let nparents = [...parents, nitem];
- if (!item.isCourseProperty && selectedPropIds.includes(item.id)) {
- propertyInfos.push(nparents);
- }
- if (item.propertyList && item.propertyList.length) {
- getProperty(item.propertyList, nparents);
- }
- });
- };
- getProperty(this.proptree, []);
- return propertyInfos;
- },
- emitChange() {
- this.selectedPropIds = this.$refs.PropertyTree.getCheckedKeys();
- const propertyInfos = this.getCheckedPropertyInfos(this.selectedPropIds);
- this.$emit("input", this.selectedPropIds);
- this.$emit("change", propertyInfos);
- },
- },
- };
- </script>
- <style lang="scss">
- .property-popover {
- &.el-popover {
- width: 300px;
- padding: 0;
- }
- &-tree {
- max-height: 300px;
- overflow: auto;
- padding: 10px;
- }
- }
- </style>
|