|
@@ -0,0 +1,590 @@
|
|
|
+<template>
|
|
|
+ <div class="task-select-tree" :style="{ width: componentWidth }">
|
|
|
+ <el-popover
|
|
|
+ ref="popover"
|
|
|
+ placement="bottom-start"
|
|
|
+ :width="popoverComputedWidth"
|
|
|
+ trigger="click"
|
|
|
+ v-model="popoverVisible"
|
|
|
+ popper-class="task-select-tree-popper"
|
|
|
+ :disabled="disabled"
|
|
|
+ @show="onPopoverShow"
|
|
|
+ >
|
|
|
+ <div class="popover-content-wrapper">
|
|
|
+ <el-input
|
|
|
+ v-if="filterable"
|
|
|
+ placeholder="输入关键字过滤"
|
|
|
+ v-model="filterText"
|
|
|
+ size="mini"
|
|
|
+ clearable
|
|
|
+ class="filter-input"
|
|
|
+ >
|
|
|
+ </el-input>
|
|
|
+ <el-scrollbar :style="{ height: treeHeight + 'px' }" class="tree-scrollbar">
|
|
|
+ <el-tree
|
|
|
+ ref="taskTree"
|
|
|
+ :data="processedTreeData"
|
|
|
+ :props="treeProps"
|
|
|
+ show-checkbox
|
|
|
+ :node-key="nodeKey"
|
|
|
+ :default-expand-all="defaultExpandAll"
|
|
|
+ :expand-on-click-node="false"
|
|
|
+ :check-strictly="checkStrictly"
|
|
|
+ :filter-node-method="filterNode"
|
|
|
+ @check="handleTreeCheck"
|
|
|
+ :default-checked-keys="tempCheckedKeys"
|
|
|
+ class="task-tree-in-popover"
|
|
|
+ >
|
|
|
+ <span class="custom-tree-node" slot-scope="{ node, data }">
|
|
|
+ <span>{{ node.label }}</span>
|
|
|
+ <span v-if="!data.isParent && showNodeDetail" class="node-detail-text">
|
|
|
+ (ID: {{ data.originalData.qwUserId}} {{ data.originalData.taskExecDate }})
|
|
|
+ </span>
|
|
|
+ </span>
|
|
|
+ </el-tree>
|
|
|
+ </el-scrollbar>
|
|
|
+ <div class="popover-footer">
|
|
|
+ <el-button size="mini" @click="handleClearInPopover">清空</el-button>
|
|
|
+ <el-button type="primary" size="mini" @click="handleConfirm">确定</el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div
|
|
|
+ slot="reference"
|
|
|
+ :class="['select-trigger-wrapper', { 'is-disabled': disabled, 'is-active': popoverVisible }]"
|
|
|
+ @mouseenter="inputHovering = true"
|
|
|
+ @mouseleave="inputHovering = false"
|
|
|
+ >
|
|
|
+ <div class="tags-or-value-container">
|
|
|
+ <template v-if="multiple && currentSelectedDisplayNodes.length > 0">
|
|
|
+ <el-tag
|
|
|
+ v-for="node in currentSelectedDisplayNodes"
|
|
|
+ :key="node[nodeKey]"
|
|
|
+ type="info"
|
|
|
+ size="small"
|
|
|
+ closable
|
|
|
+ :disable-transitions="true"
|
|
|
+ @close.stop="removeTag(node)"
|
|
|
+ class="trigger-tag"
|
|
|
+ >
|
|
|
+ {{ node[treeProps.label] }}
|
|
|
+ </el-tag>
|
|
|
+ <el-tag
|
|
|
+ v-if="currentSelectedNodes.length > maxDisplayTags"
|
|
|
+ type="info"
|
|
|
+ size="small"
|
|
|
+ class="trigger-tag"
|
|
|
+ >
|
|
|
+ + {{ currentSelectedNodes.length - maxDisplayTags }}
|
|
|
+ </el-tag>
|
|
|
+ </template>
|
|
|
+ <span v-else-if="!multiple && currentSelectedNodes.length > 0" class="single-value-display">
|
|
|
+ {{ currentSelectedNodes[0][treeProps.label] }}
|
|
|
+ </span>
|
|
|
+ <span v-else class="placeholder-text">{{ placeholder }}</span>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <span class="icons-container">
|
|
|
+ <i
|
|
|
+ v-if="showClearIcon"
|
|
|
+ class="el-icon-circle-close clear-icon"
|
|
|
+ @click.stop="handleClearOnTrigger"
|
|
|
+ ></i>
|
|
|
+ <i :class="['el-icon-arrow-up', 'arrow-icon', { 'is-reverse': !popoverVisible }]"></i>
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ </el-popover>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+export default {
|
|
|
+ name: 'SelectTree',
|
|
|
+ props: {
|
|
|
+ value: {
|
|
|
+ type: Array,
|
|
|
+ default: () => []
|
|
|
+ },
|
|
|
+ rawData: {
|
|
|
+ type: Array,
|
|
|
+ required: true
|
|
|
+ },
|
|
|
+ placeholder: {
|
|
|
+ type: String,
|
|
|
+ default: '请选择'
|
|
|
+ },
|
|
|
+ multiple: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false
|
|
|
+ },
|
|
|
+ disabled: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false
|
|
|
+ },
|
|
|
+ checkStrictly: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false
|
|
|
+ },
|
|
|
+ filterable: {
|
|
|
+ type: Boolean,
|
|
|
+ default: true
|
|
|
+ },
|
|
|
+ maxDisplayTags: {
|
|
|
+ type: Number,
|
|
|
+ default: 2
|
|
|
+ },
|
|
|
+ componentWidth: {
|
|
|
+ type: String,
|
|
|
+ default: '100%'
|
|
|
+ },
|
|
|
+ popoverWidth: {
|
|
|
+ type: [String, Number],
|
|
|
+ default: 'auto'
|
|
|
+ },
|
|
|
+ treeProps: {
|
|
|
+ type: Object,
|
|
|
+ default: () => ({
|
|
|
+ children: 'children',
|
|
|
+ label: 'label',
|
|
|
+ isLeaf: 'isLeaf'
|
|
|
+ })
|
|
|
+ },
|
|
|
+ nodeKey: {
|
|
|
+ type: String,
|
|
|
+ default: 'id'
|
|
|
+ },
|
|
|
+ defaultExpandAll: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false
|
|
|
+ },
|
|
|
+ showNodeDetail: {
|
|
|
+ type: Boolean,
|
|
|
+ default: true
|
|
|
+ },
|
|
|
+ treeHeight: {
|
|
|
+ type: Number,
|
|
|
+ default: 280
|
|
|
+ },
|
|
|
+ returnLeafOnly: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ popoverVisible: false,
|
|
|
+ filterText: '',
|
|
|
+ processedTreeData: [],
|
|
|
+ nodeMap: {},
|
|
|
+ tempCheckedKeys: [...this.value],
|
|
|
+ currentSelectedNodes: [],
|
|
|
+ inputHovering: false,
|
|
|
+ triggerElRect: null
|
|
|
+ };
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ popoverComputedWidth() {
|
|
|
+ if (this.popoverWidth === 'auto') {
|
|
|
+ return this.triggerElRect ? this.triggerElRect.width : 250;
|
|
|
+ }
|
|
|
+ return parseInt(this.popoverWidth, 10);
|
|
|
+ },
|
|
|
+ currentSelectedDisplayNodes() {
|
|
|
+ if (!this.multiple) return [];
|
|
|
+ return this.currentSelectedNodes.slice(0, this.maxDisplayTags);
|
|
|
+ },
|
|
|
+ showClearIcon() {
|
|
|
+ return (
|
|
|
+ !this.disabled &&
|
|
|
+ this.inputHovering &&
|
|
|
+ this.currentSelectedNodes.length > 0 &&
|
|
|
+ !this.multiple
|
|
|
+ );
|
|
|
+ }
|
|
|
+ },
|
|
|
+ watch: {
|
|
|
+ rawData: {
|
|
|
+ immediate: true,
|
|
|
+ handler(newData) {
|
|
|
+ this.processRawData(newData);
|
|
|
+ // 过滤掉父节点,只保留子节点
|
|
|
+ const leafOnlyKeys = this.value.filter(key => {
|
|
|
+ const node = this.nodeMap[key];
|
|
|
+ return node && !node.isParent;
|
|
|
+ });
|
|
|
+ this.updateCurrentSelectedNodesFromKeys(leafOnlyKeys, true);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ value: {
|
|
|
+ handler(newVal) {
|
|
|
+ // 过滤掉父节点,只保留子节点
|
|
|
+ const leafOnlyKeys = newVal.filter(key => {
|
|
|
+ const node = this.nodeMap[key];
|
|
|
+ return node && !node.isParent;
|
|
|
+ });
|
|
|
+
|
|
|
+ const validKeysFromNewVal = leafOnlyKeys.filter(key => this.nodeMap[key] !== undefined);
|
|
|
+ const sortedNewValStr = JSON.stringify([...leafOnlyKeys].sort());
|
|
|
+ const sortedValidKeysFromNewValStr = JSON.stringify([...validKeysFromNewVal].sort());
|
|
|
+ const currentInternalNodeKeys = this.currentSelectedNodes.map(n => n[this.nodeKey]);
|
|
|
+ const sortedCurrentInternalNodeKeysStr = JSON.stringify([...currentInternalNodeKeys].sort());
|
|
|
+
|
|
|
+ if (sortedNewValStr !== sortedValidKeysFromNewValStr) {
|
|
|
+ this.$emit('input', [...validKeysFromNewVal]);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (sortedNewValStr !== sortedCurrentInternalNodeKeysStr) {
|
|
|
+ this.tempCheckedKeys = [...leafOnlyKeys];
|
|
|
+ this.updateCurrentSelectedNodesFromKeys(validKeysFromNewVal, true);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ deep: true
|
|
|
+ },
|
|
|
+ filterText(val) {
|
|
|
+ if (this.$refs.taskTree) {
|
|
|
+ this.$refs.taskTree.filter(val);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ popoverVisible(isVisible) {
|
|
|
+ if (isVisible) {
|
|
|
+ if (this.$refs.popover && this.$refs.popover.$refs.reference) {
|
|
|
+ this.triggerElRect = this.$refs.popover.$refs.reference.getBoundingClientRect();
|
|
|
+ }
|
|
|
+ this.tempCheckedKeys = [...this.value];
|
|
|
+ this.$nextTick(() => {
|
|
|
+ if (this.$refs.taskTree) {
|
|
|
+ this.$refs.taskTree.setCheckedKeys(this.tempCheckedKeys);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ this.filterText = '';
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ // 过滤掉父节点,只保留子节点
|
|
|
+ const leafOnlyKeys = this.value.filter(key => {
|
|
|
+ const node = this.nodeMap[key];
|
|
|
+ return node && !node.isParent;
|
|
|
+ });
|
|
|
+ this.updateCurrentSelectedNodesFromKeys(leafOnlyKeys, true);
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ processRawData(data) {
|
|
|
+ if (!data || !Array.isArray(data)) {
|
|
|
+ this.processedTreeData = [];
|
|
|
+ this.nodeMap = {};
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const newMap = {};
|
|
|
+ const mapNode = (node) => {
|
|
|
+ newMap[node[this.nodeKey]] = node;
|
|
|
+ if (node[this.treeProps.children] && node[this.treeProps.children].length) {
|
|
|
+ node[this.treeProps.children].forEach(mapNode);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ this.processedTreeData = data.map(mainTask => {
|
|
|
+ const children = (mainTask.taskDetailList || []).map(detail => ({
|
|
|
+ [this.nodeKey]: detail.taskId,
|
|
|
+ [this.treeProps.label]: `${detail.qwUserId || '未命名子任务'}`,
|
|
|
+ isParent: false,
|
|
|
+ [this.treeProps.isLeaf]: true,
|
|
|
+ disabled: false, // 子节点可以选择
|
|
|
+ originalData: { ...detail, parentTaskId: mainTask.taskId }
|
|
|
+ }));
|
|
|
+
|
|
|
+ const parentNode = {
|
|
|
+ [this.nodeKey]: mainTask.taskId,
|
|
|
+ [this.treeProps.label]: mainTask.taskName,
|
|
|
+ isParent: true,
|
|
|
+ [this.treeProps.isLeaf]: children.length === 0,
|
|
|
+ disabled: true, // 父节点不可选择
|
|
|
+ [this.treeProps.children]: children,
|
|
|
+ originalData: { taskId: mainTask.taskId, taskName: mainTask.taskName }
|
|
|
+ };
|
|
|
+ mapNode(parentNode); // Add parent and its children to map
|
|
|
+ return parentNode;
|
|
|
+ });
|
|
|
+ this.nodeMap = newMap;
|
|
|
+ },
|
|
|
+ updateCurrentSelectedNodesFromKeys(keys, updateTreeVisualState = false) {
|
|
|
+ const newSelectedNodes = [];
|
|
|
+ const actualFoundKeys = [];
|
|
|
+
|
|
|
+ if (keys && Array.isArray(keys)) {
|
|
|
+ keys.forEach(key => {
|
|
|
+ const node = this.nodeMap[key];
|
|
|
+ // 只添加子节点到选中列表
|
|
|
+ if (node && !node.isParent) {
|
|
|
+ newSelectedNodes.push(node);
|
|
|
+ actualFoundKeys.push(key);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ this.currentSelectedNodes = newSelectedNodes;
|
|
|
+
|
|
|
+ if (updateTreeVisualState && this.$refs.taskTree) {
|
|
|
+ this.$refs.taskTree.setCheckedKeys([...actualFoundKeys]);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ filterNode(value, data) {
|
|
|
+ if (!value) return true;
|
|
|
+ return data[this.treeProps.label].toLowerCase().indexOf(value.toLowerCase()) !== -1;
|
|
|
+ },
|
|
|
+ handleTreeCheck(nodeData, checkStatus) {
|
|
|
+ // 如果是父节点,不允许选择
|
|
|
+ if (nodeData.isParent) {
|
|
|
+ // 恢复之前的选中状态
|
|
|
+ this.$refs.taskTree.setCheckedKeys(this.tempCheckedKeys);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!this.multiple) {
|
|
|
+ const isNodeChecked = checkStatus.checkedKeys.includes(nodeData[this.nodeKey]);
|
|
|
+ if (isNodeChecked) {
|
|
|
+ this.tempCheckedKeys = [nodeData[this.nodeKey]];
|
|
|
+ this.$refs.taskTree.setCheckedKeys([nodeData[this.nodeKey]]); // Visually enforce single check
|
|
|
+ } else {
|
|
|
+ this.tempCheckedKeys = [];
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 只保留子节点的选中状态
|
|
|
+ const leafKeys = checkStatus.checkedKeys.filter(key => {
|
|
|
+ const node = this.nodeMap[key];
|
|
|
+ return node && !node.isParent;
|
|
|
+ });
|
|
|
+ this.tempCheckedKeys = leafKeys;
|
|
|
+ // 更新树的选中状态,确保只显示子节点被选中
|
|
|
+ this.$refs.taskTree.setCheckedKeys(leafKeys);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ handleConfirm() {
|
|
|
+ let finalSelectedKeys = [];
|
|
|
+ let finalSelectedNodes = [];
|
|
|
+
|
|
|
+ if (this.$refs.taskTree) {
|
|
|
+ // 获取所有选中的节点
|
|
|
+ const allCheckedNodes = this.$refs.taskTree.getCheckedNodes();
|
|
|
+ // 只保留子节点(叶子节点)
|
|
|
+ finalSelectedNodes = allCheckedNodes.filter(node => !node.isParent);
|
|
|
+ finalSelectedKeys = finalSelectedNodes.map(node => node[this.nodeKey]);
|
|
|
+
|
|
|
+ if(!this.multiple) {
|
|
|
+ // 单选模式下,确保只选择子节点
|
|
|
+ const leafKeys = this.tempCheckedKeys.filter(key => {
|
|
|
+ const node = this.nodeMap[key];
|
|
|
+ return node && !node.isParent;
|
|
|
+ });
|
|
|
+ finalSelectedKeys = leafKeys;
|
|
|
+ finalSelectedNodes = finalSelectedKeys.map(key => this.nodeMap[key]).filter(Boolean);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ this.$emit('input', finalSelectedKeys);
|
|
|
+ this.$emit('change', finalSelectedKeys, finalSelectedNodes);
|
|
|
+ this.updateCurrentSelectedNodesFromKeys(finalSelectedKeys, true);
|
|
|
+ this.popoverVisible = false;
|
|
|
+ },
|
|
|
+ handleClearInPopover() {
|
|
|
+ this.tempCheckedKeys = [];
|
|
|
+ if (this.$refs.taskTree) {
|
|
|
+ this.$refs.taskTree.setCheckedKeys([]);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ handleClearOnTrigger() {
|
|
|
+ if (this.disabled) return;
|
|
|
+ this.tempCheckedKeys = [];
|
|
|
+ this.$emit('input', []);
|
|
|
+ this.$emit('change', [], []);
|
|
|
+ this.updateCurrentSelectedNodesFromKeys([], true);
|
|
|
+ if (this.$refs.taskTree) {
|
|
|
+ this.$refs.taskTree.setCheckedKeys([]);
|
|
|
+ }
|
|
|
+ this.popoverVisible = false;
|
|
|
+ },
|
|
|
+ removeTag(nodeToRemove) {
|
|
|
+ if (this.disabled) return;
|
|
|
+ const newKeys = this.value.filter(key => key !== nodeToRemove[this.nodeKey]);
|
|
|
+
|
|
|
+ this.$emit('input', newKeys);
|
|
|
+ this.$emit('change', newKeys, newKeys.map(k => this.nodeMap[k]).filter(Boolean));
|
|
|
+
|
|
|
+ this.tempCheckedKeys = [...newKeys];
|
|
|
+ this.updateCurrentSelectedNodesFromKeys(newKeys, true);
|
|
|
+ if (this.$refs.taskTree) {
|
|
|
+ this.$refs.taskTree.setCheckedKeys(newKeys);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ onPopoverShow() {
|
|
|
+ if (this.$refs.popover && this.$refs.popover.$refs.reference) {
|
|
|
+ this.triggerElRect = this.$refs.popover.$refs.reference.getBoundingClientRect();
|
|
|
+ }
|
|
|
+ this.tempCheckedKeys = [...this.value];
|
|
|
+ this.$nextTick(() => {
|
|
|
+ if (this.$refs.taskTree) {
|
|
|
+ this.$refs.taskTree.setCheckedKeys(this.tempCheckedKeys);
|
|
|
+ }
|
|
|
+ if (this.filterable && this.$refs.popover && this.$refs.popover.$el) {
|
|
|
+ const inputEl = this.$refs.popover.$el.querySelector('.filter-input input');
|
|
|
+ if (inputEl) inputEl.focus();
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.task-select-tree {
|
|
|
+ display: inline-block;
|
|
|
+ position: relative;
|
|
|
+ font-size: 14px;
|
|
|
+}
|
|
|
+
|
|
|
+.select-trigger-wrapper {
|
|
|
+ background-color: #fff;
|
|
|
+ border-radius: 4px;
|
|
|
+ border: 1px solid #dcdfe6;
|
|
|
+ box-sizing: border-box;
|
|
|
+ color: #606266;
|
|
|
+ display: flex; /* Use flex for alignment */
|
|
|
+ align-items: center; /* Vertically align items */
|
|
|
+ min-height: 32px; /* Element UI default input height (small) or 40px (default) */
|
|
|
+ /* Adjust line-height or padding if min-height is larger */
|
|
|
+ padding: 0 30px 0 10px; /* Space for text/tags and icons */
|
|
|
+ position: relative;
|
|
|
+ transition: border-color .2s cubic-bezier(.645,.045,.355,1);
|
|
|
+ width: 100%;
|
|
|
+ cursor: pointer;
|
|
|
+ overflow: hidden; /* Hide overflow from tags */
|
|
|
+}
|
|
|
+.select-trigger-wrapper.is-disabled {
|
|
|
+ background-color: #f5f7fa;
|
|
|
+ border-color: #e4e7ed;
|
|
|
+ color: #c0c4cc;
|
|
|
+ cursor: not-allowed;
|
|
|
+}
|
|
|
+.select-trigger-wrapper.is-disabled .trigger-tag {
|
|
|
+ background-color: #f0f2f5;
|
|
|
+ border-color: #e9e9eb;
|
|
|
+ color: #909399;
|
|
|
+}
|
|
|
+.select-trigger-wrapper.is-disabled .trigger-tag .el-tag__close {
|
|
|
+ color: #909399;
|
|
|
+}
|
|
|
+.select-trigger-wrapper:hover:not(.is-disabled) {
|
|
|
+ border-color: #c0c4cc;
|
|
|
+}
|
|
|
+.select-trigger-wrapper.is-active:not(.is-disabled) {
|
|
|
+ border-color: #409eff;
|
|
|
+}
|
|
|
+
|
|
|
+.tags-or-value-container {
|
|
|
+ flex-grow: 1; /* Allow this container to take available space */
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: wrap; /* For multiple tags */
|
|
|
+ gap: 5px; /* Space between tags */
|
|
|
+ align-items: center;
|
|
|
+ overflow: hidden; /* Prevent content from pushing icons */
|
|
|
+ padding: 2px 0; /* Small padding for tags not to touch border */
|
|
|
+}
|
|
|
+
|
|
|
+.trigger-tag {
|
|
|
+ /* margin-right: 5px; /* Use gap if supported, otherwise this */
|
|
|
+ /* margin-bottom: 2px;
|
|
|
+ margin-top: 2px; */
|
|
|
+}
|
|
|
+
|
|
|
+.single-value-display {
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ white-space: nowrap;
|
|
|
+ color: #606266;
|
|
|
+ line-height: 30px; /* Adjust if trigger height changes */
|
|
|
+}
|
|
|
+
|
|
|
+.placeholder-text {
|
|
|
+ color: #c0c4cc;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ white-space: nowrap;
|
|
|
+ line-height: 30px; /* Adjust if trigger height changes */
|
|
|
+}
|
|
|
+
|
|
|
+.icons-container {
|
|
|
+ position: absolute;
|
|
|
+ right: 5px;
|
|
|
+ top: 50%;
|
|
|
+ transform: translateY(-50%);
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ color: #c0c4cc;
|
|
|
+}
|
|
|
+.icons-container .clear-icon {
|
|
|
+ cursor: pointer;
|
|
|
+ margin-right: 5px;
|
|
|
+ display: none;
|
|
|
+ font-size: 14px;
|
|
|
+}
|
|
|
+.select-trigger-wrapper:hover .clear-icon {
|
|
|
+ /* Only show if showClearIcon is true (handled by v-if) */
|
|
|
+ display: inline-block;
|
|
|
+}
|
|
|
+.icons-container .arrow-icon {
|
|
|
+ transition: transform .3s;
|
|
|
+ font-size: 14px;
|
|
|
+}
|
|
|
+.icons-container .arrow-icon.is-reverse {
|
|
|
+ transform: rotate(180deg);
|
|
|
+}
|
|
|
+
|
|
|
+/* Popover Content */
|
|
|
+.popover-content-wrapper {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+}
|
|
|
+.filter-input {
|
|
|
+ margin-bottom: 8px;
|
|
|
+}
|
|
|
+.tree-scrollbar {
|
|
|
+ /* height is set by prop */
|
|
|
+ border: 1px solid #ebeef5;
|
|
|
+ border-radius: 2px;
|
|
|
+}
|
|
|
+.el-scrollbar__wrap { /* Make sure scrollbar wrap doesn't add extra space */
|
|
|
+ overflow-x: hidden;
|
|
|
+}
|
|
|
+.task-tree-in-popover {
|
|
|
+ min-height: 50px; /* Prevent collapse if empty */
|
|
|
+}
|
|
|
+.custom-tree-node {
|
|
|
+ flex: 1;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ font-size: 14px;
|
|
|
+ padding-right: 8px;
|
|
|
+}
|
|
|
+.node-detail-text {
|
|
|
+ font-size: 12px;
|
|
|
+ color: #909399;
|
|
|
+ margin-left: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.popover-footer {
|
|
|
+ text-align: right;
|
|
|
+ padding-top: 10px;
|
|
|
+ border-top: 1px solid #ebeef5;
|
|
|
+ margin-top: 10px;
|
|
|
+}
|
|
|
+</style>
|
|
|
+
|
|
|
+<style>
|
|
|
+/* Global style for popper to customize padding */
|
|
|
+.task-select-tree-popper.el-popover {
|
|
|
+ padding: 12px; /* Adjust padding of the popper itself */
|
|
|
+}
|
|
|
+</style>
|