index.vue 11 KB

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