App.vue 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  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. >
  46. <iframe v-if="sceneURL" :src="sceneURL" frameborder="0" :style="sceneMobileMode && {width:'375px',height:'677px'}" @load="setupSDK($event.target)"></iframe>
  47. </div>
  48. </div>
  49. <div class="app-view pointer-events-none" id="drawer-target">
  50. <n-message-provider>
  51. <n-dialog-provider>
  52. <router-view />
  53. </n-dialog-provider>
  54. </n-message-provider>
  55. </div>
  56. </n-layout-content>
  57. </n-layout>
  58. </n-layout>
  59. </n-config-provider>
  60. </template>
  61. <script setup lang="ts">
  62. import { setupSDK } from '@/sdk'
  63. import {
  64. darkTheme,
  65. lightTheme,
  66. NDialogProvider,
  67. NMessageProvider
  68. } from 'naive-ui'
  69. import { computed, ref, toRaw , watchEffect, h, onMounted, watch } from 'vue'
  70. import type { Component } from 'vue'
  71. import { useMainStore } from '@/store'
  72. import themeOverrides from '@/styles/theme.js'
  73. import { useRouter, useRoute } from 'vue-router'
  74. import {
  75. ChevronBackOutline,
  76. Layers,
  77. Cog,
  78. HomeOutline as HomeIcon,
  79. RepeatOutline,
  80. PeopleOutline,
  81. ChatboxEllipses
  82. } from '@vicons/ionicons5'
  83. const darkStore = localStorage.getItem('dark')
  84. import { RouterLink } from 'vue-router'
  85. import { NIcon, useMessage } from 'naive-ui'
  86. const route = useRoute()
  87. const activeKey = ref(route.name)
  88. const showScene = ref(false)
  89. watch(
  90. () => route.name,
  91. () => {
  92. console.log('activeKeys', route.name)
  93. activeKey.value = route.name
  94. if (route.name === 'textToaudio') {
  95. showScene.value = true
  96. } else {
  97. showScene.value = false
  98. }
  99. console.log('watch', route.name)
  100. }
  101. )
  102. const prefersDark: boolean = darkStore
  103. ? darkStore === 'true'
  104. : window.matchMedia('(prefers-color-scheme: dark)').matches
  105. const mode = ref<boolean>(prefersDark)
  106. const theme = computed(() => (mode.value ? darkTheme : lightTheme))
  107. const sceneRefWidth = computed(() => {
  108. console.log('route', route, route.name === 'basicSettings')
  109. if (route.name === 'basicSettings' || route.name === 'topicNavigation')
  110. return `calc(100% - ${240}px)`
  111. if (route.name === 'message') return `calc(100% - ${0}px)`
  112. return `calc(100% - ${mode.sceneRefWidth}px)`
  113. })
  114. const sceneURL = computed(()=>main.sceneURL)
  115. const sceneMobileMode = computed(()=>main.sceneMode == 'mobile')
  116. const sceneRef = ref()
  117. const main = useMainStore()
  118. const { setSceneLink,setSceneRef } = main
  119. watchEffect(() => {
  120. localStorage.setItem('dark', `${mode.value}`)
  121. })
  122. function renderIcon(icon: Component) {
  123. return () => h(NIcon, null, { default: () => h(icon) })
  124. }
  125. const collapsed = ref(false)
  126. const menuOptions = [
  127. {
  128. label: () =>
  129. h(
  130. RouterLink,
  131. {
  132. to: {
  133. name: 'basicSettings'
  134. // params: {
  135. // lang: 'zh-CN'
  136. // }
  137. }
  138. },
  139. { default: () => '基础设置' }
  140. ),
  141. key: 'basicSettings',
  142. icon: renderIcon(Cog)
  143. },
  144. {
  145. label: () =>
  146. h(
  147. RouterLink,
  148. {
  149. to: {
  150. name: 'digitalHuman'
  151. // params: {
  152. // lang: 'zh-CN'
  153. // }
  154. }
  155. },
  156. { default: () => '数字人播报' }
  157. ),
  158. key: 'digitalHuman',
  159. icon: renderIcon(PeopleOutline)
  160. },
  161. {
  162. label: () =>
  163. h(
  164. RouterLink,
  165. {
  166. to: {
  167. name: 'textToaudio'
  168. // params: {
  169. // lang: 'zh-CN'
  170. // }
  171. }
  172. },
  173. { default: () => '文字语音互转' }
  174. ),
  175. key: 'textToaudio',
  176. icon: renderIcon(RepeatOutline)
  177. },
  178. {
  179. label: () =>
  180. h(
  181. RouterLink,
  182. {
  183. to: {
  184. name: 'message'
  185. // params: {
  186. // lang: 'zh-CN'
  187. // }
  188. }
  189. },
  190. { default: () => '留言互动' }
  191. ),
  192. key: 'message',
  193. icon: renderIcon(ChatboxEllipses)
  194. },
  195. {
  196. label: () =>
  197. h(
  198. RouterLink,
  199. {
  200. to: {
  201. name: 'topicNavigation'
  202. // params: {
  203. // lang: 'zh-CN'
  204. // }
  205. }
  206. },
  207. { default: () => '专题导航' }
  208. ),
  209. key: 'topicNavigation',
  210. icon: renderIcon(Layers)
  211. }
  212. ]
  213. const handleUpdateValue = (value: string) => {
  214. console.log(value)
  215. }
  216. onMounted(() => {
  217. setSceneLink('/page/spg.html?m=KJ-t-3Y6dxgyehDk')
  218. setSceneRef(sceneRef.value)
  219. })
  220. </script>
  221. <style lang="sass">
  222. #app
  223. font-family: Inter, Avenir, Helvetica, Arial, sans-serif
  224. -webkit-font-smoothing: antialiased
  225. -moz-osx-font-smoothing: grayscale
  226. .layoutContent
  227. position: relative
  228. padding: 0px
  229. height: calc(100vh - 83px)
  230. overflow: hidden
  231. .app-wrap,.app-view
  232. position: absolute
  233. left: 0
  234. top: 0
  235. width: 100%
  236. height: 100%
  237. z-index: 10
  238. .app-view
  239. z-index: 100
  240. pointer-events: none
  241. .app-scene
  242. width: 100%
  243. height: 100%
  244. display: flex
  245. align-items: flex-start
  246. justify-content: center
  247. .app-scene iframe
  248. width: 100%
  249. height: 100%
  250. .required
  251. padding-left: 10px
  252. position: relative
  253. &:after
  254. content: " *"
  255. color: red
  256. position: absolute
  257. left: 0
  258. </style>