diff --git a/frontend/src/assets/style/global.less b/frontend/src/assets/style/global.less index f700fb3876..3189ad143c 100644 --- a/frontend/src/assets/style/global.less +++ b/frontend/src/assets/style/global.less @@ -190,3 +190,28 @@ body { @apply mt-0; } } + +/** 更多按钮 **/ +.ms-more-action-trigger-content { + @apply flex items-center; + .more-icon-btn { + padding: 2px; + border-radius: var(--border-radius-mini); + &:hover { + background-color: rgb(var(--primary-9)) !important; + .arco-icon { + color: rgb(var(--primary-5)) !important; + } + } + } +} +.ms-more-action-trigger-content--focus { + .more-icon-btn { + @apply !visible; + + background-color: rgb(var(--primary-9)); + .arco-icon { + color: rgb(var(--primary-5)); + } + } +} diff --git a/frontend/src/components/business/ms-tree/index.vue b/frontend/src/components/business/ms-tree/index.vue index 7900861409..b96a2b893e 100644 --- a/frontend/src/components/business/ms-tree/index.vue +++ b/frontend/src/components/business/ms-tree/index.vue @@ -629,6 +629,9 @@ &:hover { background-color: transparent; } + .ms-tree-node-extra { + background-color: transparent; + } * { color: var(--color-text-4) !important; } diff --git a/frontend/src/components/business/ms-tree/types.ts b/frontend/src/components/business/ms-tree/types.ts index 18942c2980..63f4f94217 100644 --- a/frontend/src/components/business/ms-tree/types.ts +++ b/frontend/src/components/business/ms-tree/types.ts @@ -11,6 +11,7 @@ export type MsTreeNodeData = { hideMoreAction?: boolean; // 隐藏更多操作 parentId?: string; expanded?: boolean; // 是否展开 + containChildModule?: boolean; // 包含子模块 [key: string]: any; } & TreeNodeData; diff --git a/frontend/src/components/pure/ms-table-more-action/index.vue b/frontend/src/components/pure/ms-table-more-action/index.vue index d053366f2d..8f9aa0d689 100644 --- a/frontend/src/components/pure/ms-table-more-action/index.vue +++ b/frontend/src/components/pure/ms-table-more-action/index.vue @@ -129,27 +129,4 @@ color: rgb(var(--danger-6)); } } - .ms-more-action-trigger-content { - @apply flex items-center; - .more-icon-btn { - padding: 2px; - border-radius: var(--border-radius-mini); - &:hover { - background-color: rgb(var(--primary-9)) !important; - .arco-icon { - color: rgb(var(--primary-5)) !important; - } - } - } - } - .ms-more-action-trigger-content--focus { - .more-icon-btn { - @apply !visible; - - background-color: rgb(var(--primary-9)); - .arco-icon { - color: rgb(var(--primary-5)); - } - } - } diff --git a/frontend/src/components/pure/ms-tree-select/index.vue b/frontend/src/components/pure/ms-tree-select/index.vue index 5b71bf6315..d71fccc3ed 100644 --- a/frontend/src/components/pure/ms-tree-select/index.vue +++ b/frontend/src/components/pure/ms-tree-select/index.vue @@ -44,8 +44,9 @@ @@ -92,6 +103,7 @@ import useTreeSelection from '@/components/business/ms-associate-case/useTreeSelection'; import MsTree from '@/components/business/ms-tree/index.vue'; import type { MsTreeFieldNames, MsTreeNodeData } from '@/components/business/ms-tree/types'; + import MoreMenuDropdown from './moreMenuDropdown.vue'; import { useI18n } from '@/hooks/useI18n'; import useSelect from '@/hooks/useSelect'; @@ -101,12 +113,12 @@ const props = withDefaults( defineProps<{ - data: TreeNodeData[]; fieldNames?: TreeFieldNames | MsTreeFieldNames; multiple?: boolean; shouldCalculateMaxTag?: boolean; treeCheckStrictly?: boolean; treeCheckable?: boolean; + showContainChildModule?: boolean; }>(), { shouldCalculateMaxTag: true, @@ -126,6 +138,66 @@ const { selectedModulesMaps, checkedKeys, halfCheckedKeys, selectParent, checkNode, clearSelector } = useTreeSelection(selectedModuleProps.value); + /** + * 设置子节点的属性值 + * @param trees 属性数组 + * @param targetKey 需要匹配的属性值 + */ + function updateChildNodesState(node: MsTreeNodeData, targetKey: keyof MsTreeNodeData, state: boolean) { + if (node.children) { + node.children.forEach((child: MsTreeNodeData) => { + child[targetKey] = state; + updateChildNodesState(child, targetKey, state); + }); + } + } + + function handleCheck(_checkedKeys: Array, checkedNodes: MsTreeNodeData) { + if (props.showContainChildModule) { + const realNode = findNodeByKey(treeData.value, checkedNodes.node.id, 'id'); + if (!realNode) return; + if (checkedNodes.checked) { + // 父级勾选,且父级“包含新增子模块”勾选,那么下面所有子级:禁用和勾选“包含新增子模块” + if (realNode.containChildModule) { + updateChildNodesState(realNode, 'containChildModule', true); + updateChildNodesState(realNode, 'disabled', true); + } + } else { + // 父级取消勾选,父级和所有子级“包含新增子模块”取消勾选,所有子级取消禁用 + realNode.containChildModule = false; + updateChildNodesState(realNode, 'containChildModule', false); + updateChildNodesState(realNode, 'disabled', false); + } + } + checkNode(_checkedKeys, checkedNodes); + } + + function handleSelectCurrent(nodeData: MsTreeNodeData) { + if (props.showContainChildModule && checkedKeys.value.includes(nodeData.id)) { + // 取消当前,“包含新增子模块”取消勾选,下面一层的子级取消禁用 + const realNode = findNodeByKey(treeData.value, nodeData.id, 'id'); + if (!realNode) return; + realNode.containChildModule = false; + realNode.children?.forEach((child) => { + child.disabled = false; + }); + } + selectParent(nodeData, !!checkedKeys.value.includes(nodeData.id)); + } + + function handleContainChildModule(nodeData: MsTreeNodeData, containChildModule: boolean) { + const realNode = findNodeByKey(treeData.value, nodeData.id, 'id'); + if (!realNode) return; + realNode.containChildModule = containChildModule; + if (containChildModule) { + handleCheck(checkedKeys.value, { checked: true, node: realNode }); + } else { + realNode.children?.forEach((child) => { + child.disabled = false; + }); + } + } + const skipSelectValueWatch = ref(false); watch( () => selectValue.value, @@ -170,7 +242,7 @@ } ); watch( - () => props.data, + () => treeData.value, () => { if (props.shouldCalculateMaxTag !== false && props.multiple) { calculateMaxTag(); @@ -182,11 +254,11 @@ return () => { let treeSelectTooltip = ''; const values = Array.isArray(checkedKeys.value) ? checkedKeys.value : [checkedKeys.value]; - if (props.data) { + if (treeData.value) { treeSelectTooltip = values ?.map((valueItem: string | number) => { const optItem = findNodeByKey( - props.data as MsTreeNodeData[], + treeData.value as MsTreeNodeData[], valueItem, props?.fieldNames?.key ); @@ -272,6 +344,14 @@ buffer: 15, // 缓冲区默认 10 的时候,虚拟滚动的底部 padding 计算有问题 }; }); + + const focusNodeKey = ref(''); + function setFocusKey(node: MsTreeNodeData) { + focusNodeKey.value = node.id || ''; + } + function resetFocusNodeKey() { + focusNodeKey.value = ''; + }