From 98749f73549cbbb1eb1db0916f3f2073e006384e Mon Sep 17 00:00:00 2001
From: zs <zhousong@weben-smart.com>
Date: 周三, 30 4月 2025 19:47:32 +0800
Subject: [PATCH] 托盘管理

---
 HIAWms/web/src/components/vue3-context-menu/ContextMenuUtils.ts |  158 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 158 insertions(+), 0 deletions(-)

diff --git a/HIAWms/web/src/components/vue3-context-menu/ContextMenuUtils.ts b/HIAWms/web/src/components/vue3-context-menu/ContextMenuUtils.ts
new file mode 100644
index 0000000..14c27a9
--- /dev/null
+++ b/HIAWms/web/src/components/vue3-context-menu/ContextMenuUtils.ts
@@ -0,0 +1,158 @@
+import { defineComponent, toRefs } from "vue";
+import type { VNode } from "vue";
+import type { MenuOptions } from "./ContextMenuDefine";
+import { MenuConstOptions } from "./ContextMenuDefine";
+
+/**
+ * Get absolute y position of HTMLElement
+ * @param e Element
+ * @param stopNode Specify the node for recursive termination, default to body
+ * @returns
+ */
+export function getTop(e: HTMLElement, stopNode?: HTMLElement): number {
+  let offset = e.offsetTop;
+  if (e.offsetParent != null && e.offsetParent != stopNode) {
+    offset -= e.offsetParent.scrollTop;
+    offset += getTop(e.offsetParent as HTMLElement, stopNode);
+  }
+  return offset;
+}
+/**
+ * Get absolute x position of HTMLElement
+ * @param e Element
+ * @param stopNode Specify the node for recursive termination, default to body
+ * @returns
+ */
+export function getLeft(e: HTMLElement, stopNode?: HTMLElement): number {
+  let offset = e.offsetLeft;
+  if (e.offsetParent != null && e.offsetParent != stopNode) {
+    offset -= e.offsetParent.scrollLeft;
+    offset += getLeft(e.offsetParent as HTMLElement, stopNode);
+  }
+  return offset;
+}
+
+/**
+ * If your `body` element is in a scaled state (e.g. `transform: scale(0.5)`), 
+ * this may lead to the wrong position of the menu display. 
+ * You can use this function to transform the menu display position:
+ * 
+ * ```ts
+ * 
+  import ContextMenu from '@imengyu/vue3-context-menu'
+
+  function onContextMenu(e: MouseEvent) {
+    const scaledPosition = ContextMenu.transformMenuPosition(e.target as HTMLElement, e.offsetX, e.offsetY);
+    //Full code of menuData is in `/examples/views/InScaledBody.vue`
+    menuData.x = scaledPosition.x;
+    menuData.y = scaledPosition.y;
+    //show menu
+    ContextMenu.showContextMenu(menuData);
+  }
+  * ```
+  * @param e Current click element
+  * @param offsetX MouseEvent.offsetX
+  * @param offsetY MouseEvent.offsetY
+  */
+export function transformMenuPosition(
+  e: HTMLElement,
+  offsetX: number,
+  offsetY: number,
+  container?: HTMLElement
+): {
+  x: number;
+  y: number;
+} {
+  return {
+    x: getLeft(e, container) + offsetX,
+    y: getTop(e, container) + offsetY,
+  };
+}
+
+const DEFAULT_CONTAINER_ID = "mx-menu-default-container";
+const GEN_CONTAINER_ID = "mx-menu-container-";
+let containerId = 0;
+
+export function removeContainer(container: HTMLElement): void {
+  container.parentNode?.removeChild(container);
+}
+export function genContainer(options: MenuOptions): {
+  eleId: string;
+  container: HTMLElement;
+  isNew: boolean;
+} {
+  const { getContainer, zIndex } = options;
+
+  if (getContainer) {
+    const container =
+      typeof getContainer === "function" ? getContainer() : getContainer;
+    if (container) {
+      let eleId = container.getAttribute("id");
+      if (!eleId) {
+        eleId = GEN_CONTAINER_ID + containerId++;
+        container.setAttribute("id", eleId);
+      }
+      return {
+        eleId,
+        container,
+        isNew: false,
+      };
+    }
+  }
+
+  let container = document.getElementById(DEFAULT_CONTAINER_ID);
+  if (!container) {
+    container = document.createElement("div");
+    container.setAttribute("id", DEFAULT_CONTAINER_ID);
+    container.setAttribute(
+      "class",
+      "mx-menu-ghost-host information_full_screen"
+    );
+    document.body.appendChild(container);
+  }
+  container.style.zIndex =
+    zIndex?.toString() || MenuConstOptions.defaultZindex.toString();
+  return {
+    eleId: DEFAULT_CONTAINER_ID,
+    container,
+    isNew: true,
+  };
+}
+
+/**
+ * Number to px string
+ * @param value
+ * @returns
+ */
+export function solveNumberOrStringSize(value: string | number): string {
+  return typeof value === "number" ? `${value}px` : value;
+}
+
+/**
+ * Render a VNode
+ */
+export const VNodeRender = defineComponent({
+  props: {
+    /**
+     * Can be VNode or (data: unknown) => VNode
+     */
+    vnode: {
+      type: null,
+    },
+    /**
+     * If vnode is a callback, this data will be passed to the callback first parameter.
+     * @default null
+     */
+    data: {
+      type: null,
+      default: null,
+    },
+  },
+  setup(props) {
+    const { vnode, data } = toRefs(props);
+    return () =>
+      typeof vnode.value === "function"
+        ? (vnode.value as unknown as (data: unknown) => VNode)(data.value)
+        : (vnode.value as unknown as VNode);
+  },
+});

--
Gitblit v1.9.3