index.vue 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. <template>
  2. <el-container v-loading="isAppLoadings" class="hc-layout-box" :class="[!isNullES(isLayout) && isLayout === 'no' ? 'is-no-layout' : '']">
  3. <el-header class="hc-layout-header">
  4. <div class="hc-layout-header-logo" :style="`width: ${isCollapse ? '0px' : '200px'};`" @click="logoClick">
  5. <!-- <img id="logo-icon" :src="appLogoIcon" alt=""> -->
  6. <img v-show="!isCollapse" id="logo-name" :src="appLogoName" alt="">
  7. </div>
  8. <div class="header-top-collapse-bar" @click="collapseChange">
  9. <HcIcon v-if="isCollapse" name="menu-unfold" />
  10. <HcIcon v-else name="menu-fold" />
  11. </div>
  12. <div class="header-top-menu-bar">
  13. <HcTopMenuBar @load="topMenuLoad" @change="topMenuChange" />
  14. </div>
  15. <div class="header-content-bar">
  16. <HcCascader @send="cascaderSend" @change="cascaderChange" />
  17. <hc-upload-bar />
  18. <HelpInfoBar />
  19. <ConfigBar />
  20. <UserInfoBar @load="userInfoLoad" />
  21. </div>
  22. </el-header>
  23. <el-container class="hc-layout-container">
  24. <el-aside v-if="isAsideMenu" class="hc-layout-aside" :class="[isCollapse ? 'is-collapse' : '']" :width="isCollapse ? '90px' : '200px'">
  25. <MenuBar :collapse="isCollapse" :cur="menuBarKey" :datas="menuBarData" :msg-count="msgCount" @change="menuBarChange" />
  26. </el-aside>
  27. <el-main class="hc-layout-main">
  28. <div class="hc-router-menu-bar">
  29. <RouterMenu @load="routerMenuLoad" />
  30. </div>
  31. <div id="hc-main-box" class="hc-main-page">
  32. <div class="hc-main-body">
  33. <router-view v-if="reloadRouter" v-slot="{ Component }">
  34. <transition name="fade-transform">
  35. <keep-alive :max="10">
  36. <component :is="Component" :msg-count="msgCount" />
  37. </keep-alive>
  38. </transition>
  39. </router-view>
  40. </div>
  41. </div>
  42. </el-main>
  43. </el-container>
  44. <hc-reminder v-model="isReminderShow" :text="isReminderText" />
  45. </el-container>
  46. </template>
  47. <script setup>
  48. import { nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
  49. import { useRoute, useRouter } from 'vue-router'
  50. import { getObjValue, isNullES, useClick } from 'js-fast-way'
  51. import { HcSocket } from '~src/plugins/HcSocket'
  52. import { HcAnnouncement } from 'hc-vue3-ui'
  53. import { useAppStore } from '~src/store'
  54. import { initButtons } from '~sto/app'
  55. import { useProject } from '~sto/useProject'
  56. import website from '~src/config'
  57. //初始组合式
  58. const router = useRouter()
  59. const useRoutes = useRoute()
  60. const store = useAppStore()
  61. const reloadRouter = ref(false)
  62. //获取项目信息
  63. const { isAppLoading } = useProject()
  64. //子组件
  65. import HcTopMenuBar from './modules/HcTopMenu.vue'
  66. import HcCascader from './modules/Cascader.vue'
  67. import UserInfoBar from './modules/UserInfoBar.vue'
  68. import HelpInfoBar from './modules/HelpInfoBar.vue'
  69. import ConfigBar from './modules/ConfigBar.vue'
  70. import RouterMenu from './modules/RouterMenu.vue'
  71. import MenuBar from '~src/layout/modules/MenuBar.vue'
  72. // logo
  73. const appLogoName = ref(store.getLogoName)
  74. //菜单数据
  75. const menuBarKey = ref('')
  76. const menuBarData = ref([])
  77. const isLayout = ref('')
  78. //渲染完成
  79. onMounted(() => {
  80. const layout = useRoutes?.query?.layout, layout2 = store.isLayout
  81. isLayout.value = layout ?? layout2
  82. annRefs.value = []
  83. initButtons()
  84. })
  85. //监听layout
  86. watch(() => [useRoutes?.query?.layout, store.isLayout], ([layout, layout2]) => {
  87. isLayout.value = layout ?? layout2
  88. }, { deep: true })
  89. //监听项目信息变化
  90. const isAppLoadings = ref(true)
  91. watch(() => isAppLoading.value, (res) => {
  92. if (!website.localModel) {
  93. reloadRouter.value = res
  94. isAppLoadings.value = !res
  95. } else {
  96. if (res) {
  97. setTimeout(() => {
  98. isAppLoadings.value = false
  99. }, 1000)
  100. } else {
  101. isAppLoadings.value = true
  102. }
  103. }
  104. }, { immediate:true })
  105. //路由信息
  106. const routerMenuLoad = ({ key }) => {
  107. menuBarKey.value = key
  108. }
  109. // 是否折叠
  110. const isCollapse = ref(false)
  111. const collapseChange = () => {
  112. const bool = !isCollapse.value
  113. isCollapse.value = bool
  114. store.setCollapse(bool)
  115. }
  116. //顶部菜单导航
  117. const isAsideMenu = ref(true)
  118. const topMenuLoad = () => {
  119. isAsideMenu.value = false
  120. }
  121. //顶部菜单导航被点击
  122. const topMenuChange = (data) => {
  123. if (!isNullES(data)) {
  124. menuBarData.value = data
  125. isAsideMenu.value = true
  126. }
  127. }
  128. //菜单被点击
  129. const menuBarChange = ({ code }) => {
  130. menuBarKey.value = code
  131. router.push({ name: code })
  132. }
  133. //消息数量
  134. const msgCount = ref({
  135. allCount: 0,
  136. taskCount: 0,
  137. messageCount: 0,
  138. messageCount_1: 0,
  139. messageCount_2: 0,
  140. messageCount_3: 0,
  141. messageCount_4: 0,
  142. messageCount_5: 0,
  143. })
  144. //用户信息
  145. const userId = ref('')
  146. const userInfoLoad = ({ user_id }) => {
  147. userId.value = user_id
  148. }
  149. //项目合同段的ID
  150. let socket
  151. const cascaderSend = async ({ projectId, contractId }) => {
  152. await useClick()
  153. if (isNullES(contractId)) {
  154. //本地模式
  155. if (website.localModel) {
  156. window.$message?.error('项目信息不存在,请联系管理员')
  157. reloadRouter.value = false
  158. }
  159. return
  160. }
  161. //本地模式
  162. if (website.localModel) {
  163. setTimeout(() => {
  164. reloadRouter.value = true
  165. }, 1000)
  166. } else {
  167. reloadRouter.value = true
  168. }
  169. //链接webSocket
  170. if (!isNullES(socket)) socket.close()
  171. socket = new HcSocket({ projectId, contractId, userId: userId.value }, (res) => {
  172. socketData(res?.data)
  173. })
  174. }
  175. //长链接消息
  176. let annUpdateRef
  177. const annRefs = ref([])
  178. const socketData = async (res) => {
  179. console.log('socket:', res)
  180. const { type, data } = getObjValue(res)
  181. if (type === 'msgUpdateMsg') {
  182. closeAnnUpdate()
  183. //内容为空时,代表公告已经取消,由于前面已经关闭,所以不再创建
  184. if (isNullES(data)) return
  185. await nextTick()
  186. //系统更新公告,直接替换
  187. annUpdateRef = await HcAnnouncement({ type: 'update', data: data })
  188. } else if (type === 'msgSystemMsg') {
  189. //内容为空时,代表公告已经取消,由于前面已经关闭,所以不再创建
  190. if (isNullES(data)) {
  191. closeAnnFun()
  192. return
  193. }
  194. await nextTick()
  195. //普通公告,追加公告
  196. const ref = await HcAnnouncement({ type: 'system', data: data })
  197. annRefs.value.push(ref)
  198. } else if (type === 'msgLink') {
  199. if (store.isLogin) {
  200. socket.send('getMsg')
  201. store.setIsLogin(false)
  202. }
  203. } else if (type === 'msgCountDown') {
  204. //倒计时更新
  205. if (isNullES(data) || data <= 0) {
  206. closeReminder()
  207. return
  208. }
  209. isReminderText.value = `系统将在${data}秒后,进行更新`
  210. setReminderText(data - 1)
  211. isReminderShow.value = true
  212. }
  213. }
  214. //倒计时
  215. let timeRef
  216. let startTime
  217. const isReminderShow = ref(false)
  218. const isReminderText = ref('')
  219. const setReminderText = (totalTime) => {
  220. startTime = performance.now()
  221. const step = () => {
  222. const elapsedTime = Math.floor((performance.now() - startTime) / 1000)
  223. const remainingTime = totalTime - elapsedTime
  224. if (remainingTime < 0) {
  225. closeReminder()
  226. return
  227. }
  228. isReminderText.value = `系统将在${remainingTime}秒后,进行更新`
  229. requestAnimationFrame(step)
  230. }
  231. requestAnimationFrame(step)
  232. }
  233. //关闭倒计时
  234. const closeReminder = () => {
  235. isReminderShow.value = false
  236. if (!isNullES(timeRef)) {
  237. clearTimeout(timeRef)
  238. timeRef = null
  239. }
  240. }
  241. // 项目切换
  242. const cascaderChange = () => {
  243. reloadRouter.value = false
  244. }
  245. //首页
  246. const logoClick = () => {
  247. router.push({ name: 'home-index' })
  248. }
  249. //关闭普通公告
  250. const closeAnnFun = () => {
  251. const refs = annRefs.value
  252. for (let i = 0; i < refs.length; i++) {
  253. if (!isNullES(refs[i])) {
  254. refs[i]?.close()
  255. }
  256. }
  257. annRefs.value = []
  258. }
  259. //关闭系统更新公告
  260. const closeAnnUpdate = () => {
  261. if (!isNullES(annUpdateRef)) {
  262. annUpdateRef.close()
  263. annUpdateRef = null
  264. }
  265. }
  266. //页面卸载
  267. onUnmounted(() => {
  268. if (!isNullES(socket)) socket.close()
  269. closeAnnFun()
  270. closeAnnUpdate()
  271. })
  272. </script>
  273. <style lang="scss">
  274. @import "./index.scss";
  275. </style>