header.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. <template>
  2. <div class="trademark mr-8 flex items-center text-white">
  3. <img :src="loginLogin" class="w-10 h-10 mr-4" />
  4. <div class="text-nowrap">客户管家</div>
  5. </div>
  6. <div class=" flex flex-row justify-start items-center text-white flex-1 parentDiv" ref="parentDiv">
  7. <div v-for="(routerItem, routerItemIdex) in routerList" @click="setCurrentRouter(routerItem)"
  8. :class="`border-b-2 border-transparent hover:border-white p-2 mr-4 cursor-pointer multipleyHeader ${activeRouter?.path === routerItem.path ? 'border-white' : ''}`"
  9. :key="routerItem.path" ref="childDivs" v-show="visibleItems.includes(routerItemIdex)">
  10. <div v-if="routerItem.children && routerItem.children.length <= 0 && routerItem?.isMenu" class="text-nowrap">
  11. {{ routerItem.name }}
  12. </div>
  13. <div v-if="routerItem.children && routerItem.children.length > 0" class="flex justify-center items-center">
  14. <el-dropdown>
  15. <div class="text-white w-full h-full headerText">
  16. {{ routerItem.name }}
  17. <el-icon class="el-icon--right">
  18. <arrow-down />
  19. </el-icon>
  20. </div>
  21. <template #dropdown>
  22. <el-dropdown-menu>
  23. <el-dropdown-item v-for="child in routerItem.children" :key="child.path" @click="setCurrentRouter(child)">
  24. {{ child.name }}
  25. </el-dropdown-item>
  26. </el-dropdown-menu>
  27. </template>
  28. </el-dropdown>
  29. </div>
  30. </div>
  31. <div v-if="moreRoutes.length > 0" class="flex justify-center items-center">
  32. <el-dropdown trigger="click">
  33. <span class="text-white w-full h-full headerText">
  34. <el-icon>
  35. <MoreFilled />
  36. </el-icon>
  37. </span>
  38. <template #dropdown>
  39. <el-dropdown-menu>
  40. <el-dropdown-item v-for="(child, childIndex) in moreRoutes" :key="child.path"
  41. @click="moreSetCurrentRouter(child, childIndex)">
  42. {{ child.name }}
  43. </el-dropdown-item>
  44. </el-dropdown-menu>
  45. </template>
  46. </el-dropdown>
  47. </div>
  48. </div>
  49. <div class="flex flex-row justify-start items-center text-white header-right">
  50. <el-badge :value="numberOfLogos" :max="99" class="ml-4 cursor-pointer h-[26px]" :show-zero="false">
  51. <el-icon :size="26" @click="newsDrawer = true">
  52. <Bell />
  53. </el-icon>
  54. </el-badge>
  55. <div>
  56. <img class="w- h-8 rounded-full ml-4 cursor-pointer" :src="defaultCover" alt="" @click="drawerVis = true">
  57. </div>
  58. <el-icon :size="26" class="ml-4 cursor-pointer">
  59. <Grid />
  60. </el-icon>
  61. </div>
  62. <!-- 左侧 -->
  63. <el-drawer v-model="drawerVis" modal-class="drawerVisClass" :with-header="false">
  64. <div class="w-full h-full">
  65. <div class="bg-[#075985]">
  66. <div class="p-8">
  67. <div class="w-[100px] h-[100px] p-2 border-[1px] border-[#999] rounded-full m-auto">
  68. <img class="w-full h-full" :src="defaultCover">
  69. </div>
  70. </div>
  71. <div class="text-center text-[20px] leading-none text-white pb-3">{{ userInfo.name }}</div>
  72. <div class="text-center leading-none text-slate-50 pb-3">角色:{{ userInfo.roleName }}</div>
  73. <div class="text-center leading-none text-slate-50 pb-3">公司:{{ userInfo.companyName }}</div>
  74. <div class="w-full drawerVisBtn">
  75. <div @click="logout()">退出</div>
  76. </div>
  77. </div>
  78. </div>
  79. </el-drawer>
  80. <!-- 消息 -->
  81. <el-drawer v-model="newsDrawer" modal-class="drawerVisClass" :with-header="false" size="50%">
  82. <div class="w-full h-full flex flex-row" v-loading="newsDrawerLoading">
  83. <div class="w-full h-full">
  84. <el-table :data="newsDrawerTableData" style="flex1" border>
  85. <el-table-column prop="msg" label="消息内容">
  86. <template #default="scope">
  87. <el-link type="primary" :underline="false" @click="toDetail(scope.row)">{{ scope.row.msg }}</el-link>
  88. </template>
  89. </el-table-column>
  90. <el-table-column prop="checked" label="状态" width="100">
  91. <template #default="scope">
  92. <el-tag :type="scope.row.checked ? 'success' : 'danger'">
  93. {{ scope.row.checked ? '已读' : '未读' }}
  94. </el-tag>
  95. </template>
  96. </el-table-column>
  97. <el-table-column prop="time" label="时间" width="140" />
  98. </el-table>
  99. </div>
  100. <div class="messageStyle">
  101. <el-dropdown>
  102. <span class="el-dropdown-link">
  103. <el-icon class="el-icon--right">
  104. <el-icon><MoreFilled /></el-icon>
  105. </el-icon>
  106. </span>
  107. <template #dropdown>
  108. <el-dropdown-menu>
  109. <el-dropdown-item @click="oneClickRead()" :disabled="numberOfLogos <= 0">一键已读</el-dropdown-item>
  110. </el-dropdown-menu>
  111. </template>
  112. </el-dropdown>
  113. </div>
  114. </div>
  115. </el-drawer>
  116. </template>
  117. <!-- /information/list -->
  118. <script lang="ts" setup>
  119. import { onMounted, ref, watchEffect, watch } from 'vue';
  120. import { RouteRecordRaw, useRouter, useRoute } from 'vue-router';
  121. import { useStore } from "../../store/index"
  122. import { post, uploadFile } from "@/utils/request";
  123. import defaultCover from "../../assets/defaultCover.png";
  124. import { formatDate } from '@/utils/times'
  125. import loginLogin from '../../assets/login/login_logo.png'
  126. const { routers, clearStore, userInfo } = useStore()
  127. const router = useRouter();
  128. const route = useRoute()
  129. // const routerList = ref<RouteRecordRaw[]>([]);
  130. const routerList = ref<any[]>([]);
  131. const activeRouter = ref<RouteRecordRaw>();
  132. const visibleItems = ref<number[]>([]);
  133. const parentDiv = ref<HTMLElement | null>(null);
  134. const itemLastIndex = ref(0)
  135. const moreRoutes = ref<any[]>([])
  136. const newsDrawerTableData = ref<any[]>([])
  137. const drawerVis = ref(false)
  138. const newsDrawer = ref(false)
  139. const newsDrawerLoading = ref(false)
  140. const numberOfLogos = ref(0)
  141. const updateVisibleItems = () => {
  142. const parentWidth = (parentDiv.value?.offsetWidth && parentDiv.value?.offsetWidth - 150) || 10;
  143. const canvas = document.createElement('canvas');
  144. const context = canvas.getContext('2d');
  145. let textWidthList: any = [] // 所有文字的宽度
  146. let totalWidth = 0;
  147. let temporaryIndex: any = []
  148. if (context) {
  149. context.font = '16px 微软雅黑';
  150. textWidthList = routerList.value.map((item: any) => {
  151. const metrics = context.measureText(item.name);
  152. return Math.ceil(metrics.width) + 32; // 32是padding和margin的宽度
  153. })
  154. }
  155. for (let i in textWidthList) {
  156. if (totalWidth + textWidthList[i] > parentWidth) {
  157. break;
  158. }
  159. totalWidth += textWidthList[i];
  160. temporaryIndex.push(+i);
  161. }
  162. // 替换最后一个元素
  163. const lastIndex = routerList.value.findIndex(obj => obj.name === '系统设置');
  164. itemLastIndex.value = lastIndex
  165. temporaryIndex.splice(temporaryIndex.length - 1, 1, lastIndex)
  166. visibleItems.value = temporaryIndex;
  167. // 过滤出隐藏的元素
  168. let interceptIndex = Object.values(visibleItems.value).findIndex(v => +v == lastIndex)
  169. let newVisibleItems = JSON.parse(JSON.stringify(temporaryIndex)).splice(0, interceptIndex + 1)
  170. let missingIndex = findMissingNumbers(newVisibleItems)
  171. let routerLists = []
  172. for (var i in missingIndex) {
  173. routerLists.push(routerList.value[missingIndex[i]])
  174. }
  175. moreRoutes.value = routerLists
  176. // 判断当前的索引是否在隐藏元素中
  177. let currentIndex = moreRoutes.value.findIndex(obj => obj.name === activeRouter.value?.name);
  178. if (currentIndex >= 0) {
  179. replaceData(activeRouter.value, currentIndex)
  180. }
  181. };
  182. const findMissingNumbers = (arr: any) => {
  183. let missingNumbers = [];
  184. arr.sort((a: any, b: any) => a - b); // 对数组进行排序
  185. for (let i = arr[0]; i < arr[arr.length - 1]; i++) {
  186. if (!arr.includes(i)) { // 如果数组中不包含当前数字
  187. missingNumbers.push(i); // 将缺失的数字添加到结果数组中
  188. }
  189. }
  190. return missingNumbers;
  191. }
  192. const setCurrentRouter = (item: RouteRecordRaw) => {
  193. activeRouter.value = item;
  194. if (item.children && item.children.length > 0) {
  195. router.push({ path: item.children[0].path });
  196. return
  197. }
  198. router.push({ path: item.path });
  199. };
  200. const moreSetCurrentRouter = (item: RouteRecordRaw, index: any) => {
  201. activeRouter.value = item;
  202. router.push({ path: item.path });
  203. replaceData(item, index)
  204. };
  205. const replaceData = (item: any, index: any) => {
  206. let itemIndex = routerList.value.findIndex(v => v.name == item.name)
  207. let lastItem = routerList.value[visibleItems.value[visibleItems.value.length - 2]]
  208. visibleItems.value.splice(visibleItems.value.length - 2, 1, itemIndex),
  209. moreRoutes.value.splice(index, 1, lastItem)
  210. }
  211. const logout = () => {
  212. clearStore();
  213. router.push({ path: '/login' });
  214. };
  215. const getNewsDrawerTableData = () => {
  216. newsDrawerLoading.value = true
  217. post(`/information/list`, {}).then(res => {
  218. const data = res.data.map((item: any) => {
  219. return {
  220. ...item,
  221. time: formatDate(new Date(item.time))
  222. }
  223. })
  224. numberOfLogos.value = (data || []).filter((item: any) => !item.checked).length
  225. newsDrawerTableData.value = data
  226. }).catch(err => {
  227. newsDrawerTableData.value = []
  228. console.log(err)
  229. }).finally(() => {
  230. newsDrawerLoading.value = false
  231. })
  232. }
  233. const oneClickRead = () => {
  234. newsDrawerLoading.value = true
  235. post(`/information/checkAll`).then(_res => {
  236. getNewsDrawerTableData()
  237. }).catch(err => {
  238. console.log(err, '<==== 失败')
  239. }).finally(() => {
  240. newsDrawerLoading.value = false
  241. })
  242. }
  243. const toDetail = (row: any) => {
  244. console.log(row, '<=== 点击数据')
  245. const { id, type, path } = row
  246. post(`/information/check`, { id }).then(res => {
  247. console.log(res, '<=== 成功')
  248. getNewsDrawerTableData()
  249. if (path) {
  250. router.push({ path });
  251. }
  252. }).catch(err => {
  253. console.log(err, '<==== 失败')
  254. }).finally(() => {
  255. newsDrawer.value = false
  256. })
  257. }
  258. onMounted(() => {
  259. getNewsDrawerTableData()
  260. routerList.value = routers;
  261. activeRouter.value = routerList.value.find((item) => item.path === router.currentRoute.value.path);
  262. window.addEventListener('resize', updateVisibleItems);
  263. setTimeout(() => {
  264. updateVisibleItems();
  265. }, 500);
  266. })
  267. watchEffect(() => {
  268. watch(() => route.path, (newPath, _oldPath) => {
  269. activeRouter.value = routerList.value.find((item) => item.path === newPath);
  270. }, {
  271. immediate: false
  272. }
  273. );
  274. });
  275. </script>
  276. <style scoped lang="scss">
  277. .messageStyle {
  278. margin: 15px;
  279. margin-left: 100px;
  280. }
  281. .trademark {
  282. font-size: 20px;
  283. }
  284. .multipleyHeader {
  285. height: 96%;
  286. display: flex;
  287. align-items: center;
  288. text-wrap: nowrap;
  289. .headerText {
  290. font-size: 16px;
  291. }
  292. }
  293. .parentBox {
  294. // max-width: 80%;
  295. // min-width: 300px;
  296. flex: 1;
  297. overflow: hidden;
  298. }
  299. .header-right {
  300. width: 135px;
  301. }
  302. .parentDiv {
  303. width: 10%;
  304. }
  305. .drawerVisClass {
  306. .drawerVisBtn {
  307. margin-top: 10px;
  308. border-top: 1px solid #999;
  309. div {
  310. text-align: center;
  311. line-height: 40px;
  312. color: #fff;
  313. cursor: pointer;
  314. &:hover {
  315. background: #086597;
  316. }
  317. }
  318. }
  319. }
  320. </style>