pane.vue 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. <template>
  2. <ActionMenus
  3. v-if="!store.child.value"
  4. class="menus abc"
  5. :class="{ level: level === 2 }"
  6. :menus="store.menus"
  7. :active-key="store.activeMenuKey.value"
  8. dire="column"
  9. />
  10. <scene-menus
  11. :parentKey="store.activeMenuKey.value"
  12. @active="(data) => (childActive = data)"
  13. v-if="store.child.value"
  14. @back="store.child.value = null"
  15. :menus="store.child.value"
  16. :level="level + 1"
  17. />
  18. </template>
  19. <script lang="ts" setup>
  20. import ActionMenus from "@/components/group-button/index.vue";
  21. import { generateMixMenus, MenuRaw, menus, findMenuByKey } from "./menus";
  22. import { joinActions } from "./actions";
  23. import { computed, onMounted, onUnmounted, ref, watchEffect } from "vue";
  24. import { disabledMap, laserModeStack } from "@/hook";
  25. import { Mode } from "@/sdk";
  26. const props = withDefaults(
  27. defineProps<{ menus?: MenuRaw[]; level?: number; parentKey?: string }>(),
  28. { level: 1 }
  29. );
  30. const emit = defineEmits<{
  31. (e: "back"): void;
  32. (e: "active", data: string[]): void;
  33. (e: "enterChild"): void;
  34. (e: "leaveChild"): void;
  35. }>();
  36. const backMenu = {
  37. icon: "return",
  38. text: "",
  39. key: "back",
  40. onClick: () => emit("back"),
  41. };
  42. const menusMix = computed(() => (props.level === 1 ? menus : [backMenu, ...props.menus]));
  43. const store = generateMixMenus("children", (m) => m, menusMix.value);
  44. const childActive = ref<string[]>([]);
  45. watchEffect(() => {
  46. const currentActive = store.activeMenuKey.value || store.itemActiveKey.value;
  47. console.log(props.level, currentActive);
  48. if (currentActive) {
  49. emit("active", [currentActive, ...childActive.value]);
  50. } else {
  51. emit("active", []);
  52. }
  53. });
  54. watchEffect(() => {
  55. const menu = findMenuByKey(store.itemActiveKey.value as any);
  56. if (menu?.disabled && menu?.disabled()) {
  57. store.itemActiveKey.value = null;
  58. }
  59. });
  60. watchEffect((onCleanup) => {
  61. const menu = store.activeMenuKey.value && findMenuByKey(store.activeMenuKey.value);
  62. if (store.child && menu?.onClick) {
  63. const leaveHook = menu.onClick();
  64. leaveHook && onCleanup(leaveHook);
  65. } else {
  66. onCleanup(() => {});
  67. }
  68. });
  69. if (props.level === 1) {
  70. watchEffect(() => {
  71. disabledMap.photo = !store.child.value?.length;
  72. });
  73. watchEffect(() => {
  74. if (store.child.value) {
  75. emit("enterChild");
  76. } else {
  77. emit("leaveChild");
  78. }
  79. });
  80. }
  81. const stopWatch = joinActions(store.itemActiveKey);
  82. onUnmounted(() => {
  83. stopWatch();
  84. if (props.parentKey === "measure") {
  85. laserModeStack.pop();
  86. }
  87. });
  88. onMounted(() => {
  89. if (props.level > 1) {
  90. const defaultMenu = props.menus.find((menu) => {
  91. if (typeof menu.defaultSelect === "function") {
  92. return menu.defaultSelect();
  93. } else {
  94. return menu.defaultSelect;
  95. }
  96. });
  97. store.itemActiveKey.value = defaultMenu?.key;
  98. // store.activeMenuKey.value =
  99. if (props.parentKey === "measure") {
  100. laserModeStack.push(ref(Mode.cloud));
  101. }
  102. }
  103. });
  104. </script>
  105. <script lang="ts">
  106. export default { name: "scene-menus" };
  107. </script>
  108. <style lang="scss" scoped>
  109. .menus {
  110. position: absolute;
  111. left: var(--boundMargin);
  112. top: 50%;
  113. transform: translateY(-50%);
  114. z-index: 2;
  115. }
  116. </style>
  117. <style lang="scss">
  118. .level div:first-child {
  119. background-color: rgba(255, 255, 255, 0.3);
  120. height: 50px;
  121. width: 50px;
  122. min-width: 50px;
  123. border-radius: 50%;
  124. margin-bottom: 30px !important;
  125. position: relative;
  126. i {
  127. font-size: 16px !important;
  128. }
  129. &:after {
  130. position: absolute;
  131. content: "";
  132. height: 1px;
  133. left: 10px;
  134. right: 10px;
  135. bottom: -15px;
  136. background-color: rgba(255, 255, 255, 0.2);
  137. }
  138. }
  139. </style>