App.vue 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. <template>
  2. <n-config-provider
  3. data-cy="app"
  4. :theme="theme"
  5. :theme-overrides="themeOverrides"
  6. :class="{ dark: mode }"
  7. >
  8. <n-layout position="absolute" style="height: 100vh">
  9. <n-layout-header style="padding: 24px" bordered>
  10. <div class="flex justify-between items-center">
  11. <div class="back" style="position: relative; top: 4px; color: #fff">
  12. <n-icon size="24" :component="ChevronBackOutline" />
  13. <span style="position: relative; top: -6px">返回我的场景</span>
  14. </div>
  15. <n-button type="primary"> 保存 </n-button>
  16. </div>
  17. </n-layout-header>
  18. <n-layout
  19. class="bg-white dark:bg-gray-800 dark:text-white text-gray-800 h-screen w-screen"
  20. position="absolute"
  21. style="top: 83px; bottom: 64px"
  22. has-sider
  23. >
  24. <!-- collapse-mode="transform"
  25. @mouseover="collapsed = false"
  26. @mouseleave="collapsed = true" -->
  27. <n-layout-sider
  28. data-cy="sidebar"
  29. :width="180"
  30. :collapsed="collapsed"
  31. :native-scrollbar="false"
  32. bordered
  33. >
  34. <n-menu class="menu-class" style="--n-item-color-hover: rgb(243, 243, 245, .5);--n-item-text-color: white; --n-font-size: 14px;--n-item-icon-color: #fff; --n-item-icon-color-active: #316c72;" v-model:value="activeKey" :options="menuOptions" @update:value="handleUpdateValue" />
  35. </n-layout-sider>
  36. <n-layout-content
  37. content-class="layoutContent"
  38. :native-scrollbar="false"
  39. >
  40. <div class="app-wrap">
  41. <div
  42. class="app-scene"
  43. ref="sceneRef"
  44. :style="{ width: sceneRefWidth, opacity: showScene ? 0 : 1 }"
  45. ></div>
  46. </div>
  47. <div class="app-view pointer-events-none" id="drawer-target">
  48. <n-message-provider>
  49. <n-dialog-provider>
  50. <router-view />
  51. </n-dialog-provider>
  52. </n-message-provider>
  53. </div>
  54. </n-layout-content>
  55. </n-layout>
  56. </n-layout>
  57. </n-config-provider>
  58. </template>
  59. <script setup lang="ts">
  60. import { useSDK } from '@/sdk'
  61. import {
  62. darkTheme,
  63. lightTheme,
  64. NDialogProvider,
  65. NMessageProvider
  66. } from 'naive-ui'
  67. import { computed, ref, toRaw , watchEffect, h, onMounted, watch } from 'vue'
  68. import type { Component } from 'vue'
  69. import { useMainStore } from '@/store'
  70. import themeOverrides from '@/styles/theme.js'
  71. import { useRouter, useRoute } from 'vue-router'
  72. import {
  73. ChevronBackOutline,
  74. Layers,
  75. Cog,
  76. HomeOutline as HomeIcon,
  77. RepeatOutline,
  78. PeopleOutline,
  79. ChatboxEllipses
  80. } from '@vicons/ionicons5'
  81. const darkStore = localStorage.getItem('dark')
  82. import { RouterLink } from 'vue-router'
  83. import { NIcon, useMessage } from 'naive-ui'
  84. const route = useRoute()
  85. const activeKey = ref(route.name)
  86. const showScene = ref(false)
  87. watch(
  88. () => route.name,
  89. () => {
  90. console.log('activeKeys', route.name)
  91. activeKey.value = route.name
  92. if (route.name === 'textToaudio') {
  93. showScene.value = true
  94. } else {
  95. showScene.value = false
  96. }
  97. console.log('watch', route.name)
  98. }
  99. )
  100. const prefersDark: boolean = darkStore
  101. ? darkStore === 'true'
  102. : window.matchMedia('(prefers-color-scheme: dark)').matches
  103. const mode = ref<boolean>(prefersDark)
  104. const theme = computed(() => (mode.value ? darkTheme : lightTheme))
  105. const sceneRefWidth = computed(() => {
  106. console.log('route', route, route.name === 'basicSettings')
  107. if (route.name === 'basicSettings' || route.name === 'topicNavigation')
  108. return `calc(100% - ${240}px)`
  109. if (route.name === 'message') return `calc(100% - ${0}px)`
  110. return `calc(100% - ${mode.sceneRefWidth}px)`
  111. })
  112. const sceneRef = ref()
  113. const main = useMainStore()
  114. const { setSceneRef } = main
  115. watchEffect(() => {
  116. localStorage.setItem('dark', `${mode.value}`)
  117. })
  118. function renderIcon(icon: Component) {
  119. return () => h(NIcon, null, { default: () => h(icon) })
  120. }
  121. const collapsed = ref(false)
  122. const menuOptions = [
  123. {
  124. label: () =>
  125. h(
  126. RouterLink,
  127. {
  128. to: {
  129. name: 'basicSettings'
  130. // params: {
  131. // lang: 'zh-CN'
  132. // }
  133. }
  134. },
  135. { default: () => '基础设置' }
  136. ),
  137. key: 'basicSettings',
  138. icon: renderIcon(Cog)
  139. },
  140. {
  141. label: () =>
  142. h(
  143. RouterLink,
  144. {
  145. to: {
  146. name: 'digitalHuman'
  147. // params: {
  148. // lang: 'zh-CN'
  149. // }
  150. }
  151. },
  152. { default: () => '数字人播报' }
  153. ),
  154. key: 'digitalHuman',
  155. icon: renderIcon(PeopleOutline)
  156. },
  157. {
  158. label: () =>
  159. h(
  160. RouterLink,
  161. {
  162. to: {
  163. name: 'textToaudio'
  164. // params: {
  165. // lang: 'zh-CN'
  166. // }
  167. }
  168. },
  169. { default: () => '文字语音互转' }
  170. ),
  171. key: 'textToaudio',
  172. icon: renderIcon(RepeatOutline)
  173. },
  174. {
  175. label: () =>
  176. h(
  177. RouterLink,
  178. {
  179. to: {
  180. name: 'message'
  181. // params: {
  182. // lang: 'zh-CN'
  183. // }
  184. }
  185. },
  186. { default: () => '留言互动' }
  187. ),
  188. key: 'message',
  189. icon: renderIcon(ChatboxEllipses)
  190. },
  191. {
  192. label: () =>
  193. h(
  194. RouterLink,
  195. {
  196. to: {
  197. name: 'topicNavigation'
  198. // params: {
  199. // lang: 'zh-CN'
  200. // }
  201. }
  202. },
  203. { default: () => '专题导航' }
  204. ),
  205. key: 'topicNavigation',
  206. icon: renderIcon(Layers)
  207. }
  208. ]
  209. const handleUpdateValue = (value: string) => {
  210. console.log(value)
  211. }
  212. const sdk = useSDK()
  213. sdk.use('MinMap')
  214. onMounted(() => {
  215. sdk.mount(sceneRef.value)
  216. sdk.render()
  217. setSceneRef(sceneRef.value)
  218. })
  219. </script>
  220. <style lang="sass">
  221. #app
  222. font-family: Inter, Avenir, Helvetica, Arial, sans-serif
  223. -webkit-font-smoothing: antialiased
  224. -moz-osx-font-smoothing: grayscale
  225. .layoutContent
  226. position: relative
  227. padding: 0px
  228. height: calc(100vh - 83px)
  229. overflow: hidden
  230. .app-wrap,.app-view
  231. position: absolute
  232. left: 0
  233. top: 0
  234. width: 100%
  235. height: 100%
  236. z-index: 10
  237. .app-view
  238. z-index: 100
  239. pointer-events: none
  240. .app-scene
  241. width: 100%
  242. height: 100%
  243. [xui_min_map]
  244. right: 10px
  245. top: 10px
  246. .required
  247. padding-left: 10px
  248. position: relative
  249. &:after
  250. content: " *"
  251. color: red
  252. position: absolute
  253. left: 0
  254. </style>