index-mt.vue 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. <template>
  2. <div style="height: 100%; width: 100%; display: flex; flex-direction: row;">
  3. <!-- 左边是列表 -->
  4. <div style="width: 300px; height: 100%;">
  5. <el-card style="height: 100%;">
  6. <template #header>
  7. <div class="card-header">
  8. <el-icon :size="15" class="mr-2" style="vertical-align: middle;">
  9. <component :is="Menu" />
  10. </el-icon>
  11. <span>项目列表</span>
  12. </div>
  13. </template>
  14. <el-menu
  15. :key="menuKey"
  16. :default-active="activePath"
  17. :default-openeds="defaultOpeneds"
  18. class="custom-menu"
  19. mode="vertical"
  20. @select="handleMenuSelect"
  21. >
  22. <el-sub-menu
  23. v-for="(parent, parentIndex) in menuItems"
  24. :key="parentIndex"
  25. :index="parent.index"
  26. :class="{ 'parent-active': isParentActive(parent.index) }"
  27. >
  28. <template #title>
  29. <!-- 父菜单图标 -->
  30. <el-icon :size="18" class="mr-2">
  31. <component :is="parent.icon" />
  32. </el-icon>
  33. <span>{{ parent.title }}</span>
  34. </template>
  35. <el-menu-item
  36. v-for="(child, childIndex) in parent.children"
  37. :key="childIndex"
  38. :index="child.index"
  39. >
  40. <!-- 子菜单图标 -->
  41. <el-icon :size="18" class="mr-2">
  42. <component :is="child.icon" />
  43. </el-icon>
  44. <span>{{ child.title }}</span>
  45. </el-menu-item>
  46. </el-sub-menu>
  47. </el-menu>
  48. </el-card>
  49. </div>
  50. <!-- 右边是地图引擎 -->
  51. <map-editor ref="mapEditor" :refname="'rtWatch'" id="me" class="map-editor" ></map-editor>
  52. </div>
  53. </template>
  54. <script setup lang="ts">
  55. import { ref, onMounted, computed, onUnmounted } from "vue";
  56. import MapEditor from '@/components/MapEditor/index.vue'
  57. // 导入 Element Plus 内置图标
  58. import {
  59. Folder,
  60. Menu,
  61. } from '@element-plus/icons-vue';
  62. const mapEditor = ref(null)
  63. const vGlobal = window.vueGlobal;
  64. // 菜单数据
  65. const menuItems = [
  66. {
  67. index: '1',
  68. title: '父菜单1',
  69. icon: Menu,
  70. children: [
  71. { index: '1-1', title: '子菜单1-1', icon: Folder }
  72. ]
  73. }
  74. ];
  75. const menuKey = ref(0);
  76. let dictMenus = {};
  77. // 当前选中的路径
  78. const activePath = ref('');
  79. // 计算所有父菜单的索引,用于默认展开所有子菜单
  80. const defaultOpeneds = computed(() => {
  81. // 提取所有父菜单的 index 组成数组
  82. return menuItems.map(item => item.index);
  83. });
  84. let scheduleId = null;
  85. const createMenus = () => {
  86. menuItems.splice(0);
  87. dictMenus = {};
  88. for (const p of vGlobal.vecProject) {
  89. const pIdx = '' + p.id;
  90. menuItems.push({
  91. index: pIdx,
  92. title: p.name,
  93. icon: Menu,
  94. children: []
  95. });
  96. dictMenus[pIdx] = p;
  97. for (const m of p.locations) {
  98. const mIdx = pIdx + '-' + m.id;
  99. menuItems[menuItems.length - 1].children.push({
  100. index: mIdx,
  101. title: m.name,
  102. icon: Folder
  103. });
  104. dictMenus[mIdx] = m;
  105. }
  106. }
  107. menuKey.value++;
  108. };
  109. // 处理菜单选中事件
  110. const handleMenuSelect = (index) => {
  111. activePath.value = index;
  112. console.log('handleMenuSelect', index, dictMenus[index]);
  113. const location = dictMenus[index];
  114. if (location) {
  115. vGlobal.mapEngine.focusPt(location.center.x, location.center.y);
  116. }
  117. };
  118. // 判断父菜单是否需要激活样式
  119. const isParentActive = (parentIndex) => {
  120. // 检查当前选中项是否属于该父菜单
  121. return activePath.value.startsWith(parentIndex + '-');
  122. };
  123. const handleOpen = (key: string, keyPath: string[]) => {
  124. console.log(key, keyPath)
  125. }
  126. const handleClose = (key: string, keyPath: string[]) => {
  127. console.log(key, keyPath)
  128. }
  129. const schedule = () => {
  130. if (!vGlobal.isInited()) {
  131. return;
  132. }
  133. console.log('schedule loop' + new Date().toLocaleTimeString());
  134. };
  135. onMounted(() => {
  136. const ci = setInterval(() => {
  137. if (vGlobal.isInited()) {
  138. clearInterval(ci);
  139. createMenus();
  140. }
  141. }, 100);
  142. console.log('onMounted');
  143. scheduleId = setInterval(() => {
  144. schedule();
  145. }, 1000);
  146. });
  147. onUnmounted(() => {
  148. clearInterval(scheduleId);
  149. console.log('onUnmounted');
  150. scheduleId = null;
  151. });
  152. </script>
  153. <style scoped>
  154. .custom-menu {
  155. width: 100%;
  156. }
  157. :deep(.el-sub-menu .el-menu-item.is-active) {
  158. color: #0557aa !important;
  159. background-color: #e6f7ff !important;
  160. }
  161. /* 子菜单选中样式 */
  162. :deep(.el-menu-item.is-active) {
  163. color: #0557aa !important;
  164. background-color: #e6f7ff !important;
  165. font-weight: 600;
  166. }
  167. /* 父菜单激活样式 - 当子菜单选中时 */
  168. :deep(.parent-active .el-sub-menu__title) {
  169. color: #0557aa !important;
  170. font-weight: bold;
  171. }
  172. /* 父菜单 hover 样式保持一致 */
  173. :deep(.el-sub-menu__title:hover) {
  174. color: #0557aa !important;
  175. }
  176. </style>