ManagementInterface.vue 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. <template>
  2. <div class="home-container">
  3. <div class="box-1">
  4. <div class="inner-box left-box">
  5. <div class="app-header">
  6. <img :src="LogoImage" alt="Logo" class="app-logo" />
  7. <span>{{ platformTitle }}</span>
  8. </div>
  9. </div>
  10. <div class="inner-box right-box">
  11. <div class="top-right-box">
  12. <UserInfoPopover />
  13. </div>
  14. </div>
  15. </div>
  16. <div class="main-content">
  17. <div class="inner-content">
  18. <div
  19. class="small-box"
  20. v-if="hasAiCoursePermission"
  21. @click="navigateToHome(aiCourseRoutes.home)"
  22. :style="{ backgroundImage: `url(${enlightenment})` }"
  23. >
  24. <div class="box-logout-btn">AI启蒙课<el-icon class="arrow-icon"><DArrowRight /></el-icon></div>
  25. </div>
  26. <div
  27. class="small-box"
  28. v-if="hasHomePermission"
  29. @click="navigateToHome(homeRoutes.home)"
  30. :style="{ backgroundImage: `url(${programming})` }"
  31. >
  32. <div class="box-logout-btn" >AI通识课<el-icon class="arrow-icon"><DArrowRight /></el-icon></div>
  33. </div>
  34. <div
  35. class="small-box"
  36. v-if="hasBlocklyPermission"
  37. @click="navigateToHome(blocklyRoutes.home)"
  38. :style="{ backgroundImage: `url(${general})` }"
  39. >
  40. <div class="box-logout-btn">AI编程课<el-icon class="arrow-icon"><DArrowRight /></el-icon></div>
  41. </div>
  42. </div>
  43. <!-- <div class="home-buttons">
  44. <el-button
  45. v-if="hasHomePermission"
  46. type="primary"
  47. @click="navigateToHome(homeRoutes.home)"
  48. class="home-button"
  49. >
  50. 通识课首页
  51. </el-button>
  52. <el-button
  53. v-if="hasBlocklyPermission"
  54. type="success"
  55. @click="navigateToHome(blocklyRoutes.home)"
  56. class="home-button"
  57. >
  58. Blockly编程课首页
  59. </el-button>
  60. <el-button
  61. v-if="hasAiCoursePermission"
  62. type="warning"
  63. @click="navigateToHome(aiCourseRoutes.home)"
  64. class="home-button"
  65. >
  66. AI实验课首页
  67. </el-button>
  68. </div> -->
  69. </div>
  70. </div>
  71. </template>
  72. <script setup>
  73. import { ref, onMounted, computed } from 'vue'
  74. import { useRouter } from 'vue-router'
  75. import UserInfoPopover from '@/components/user/UserInfoPopover.vue'
  76. import { homeRoutes, blocklyRoutes, aiCourseRoutes, managementRoutes } from '@/router'
  77. import { CONFIG } from '@/utils/roleUtils.js'
  78. import { Message } from '@/utils/message/Message.js'
  79. import { DArrowRight } from '@element-plus/icons-vue'
  80. // 背景图
  81. // Logo
  82. import LogoImage from '@/assets/images/logo.png'
  83. // 启蒙课
  84. import enlightenment from '@/assets/manage/enlightenment.png'
  85. // 编程课
  86. import programming from '@/assets/manage/programming02.png'
  87. // 通识课
  88. import general from '@/assets/manage/general02.png'
  89. // 平台标题响应式变量
  90. const platformTitle = ref(import.meta.env.VITE_APP_TITLE)
  91. // 获取当前路由对象
  92. const router = useRouter()
  93. // 计算用户权限
  94. const hasHomePermission = computed(() => {
  95. const roleRouteStr = localStorage.getItem(CONFIG.USER_ROLE_ROUTE_KEY)
  96. const roleRouteSet = roleRouteStr ? JSON.parse(roleRouteStr) : []
  97. return roleRouteSet.includes(homeRoutes.role)
  98. })
  99. const hasBlocklyPermission = computed(() => {
  100. const roleRouteStr = localStorage.getItem(CONFIG.USER_ROLE_ROUTE_KEY)
  101. const roleRouteSet = roleRouteStr ? JSON.parse(roleRouteStr) : []
  102. return roleRouteSet.includes(blocklyRoutes.role)
  103. })
  104. const hasAiCoursePermission = computed(() => {
  105. // const roleRouteStr = localStorage.getItem(CONFIG.USER_ROLE_ROUTE_KEY)
  106. // const roleRouteSet = roleRouteStr ? JSON.parse(roleRouteStr) : []
  107. // return roleRouteSet.includes(aiCourseRoutes.role)
  108. return false
  109. })
  110. // 更新平台标题
  111. const updatePlatformTitle = () => {
  112. platformTitle.value = localStorage.getItem('tenantName') || import.meta.env.VITE_APP_DEFAULT_LOGIN_TENANT
  113. }
  114. // 导航到对应首页
  115. const navigateToHome = (path) => {
  116. router.push(path)
  117. }
  118. onMounted(() => {
  119. // 初始化平台标题
  120. updatePlatformTitle()
  121. // storage事件监听器,监听其他标签页对localStorage的修改
  122. window.addEventListener('storage', (e) => {
  123. if (e.key === 'tenantName') {
  124. updatePlatformTitle()
  125. }
  126. })
  127. })
  128. // 全局:更新租户名称
  129. window.updateTenantName = (newName) => {
  130. localStorage.setItem('tenantName', newName)
  131. updatePlatformTitle()
  132. }
  133. </script>
  134. <style scoped lang="scss">
  135. @use 'sass:math';
  136. @function rpx($px) {
  137. @return math.div($px, 750) * 100vw;
  138. }
  139. .home-container {
  140. position: fixed;
  141. top: 0;
  142. left: 0;
  143. right: 0;
  144. bottom: 0;
  145. background: url('@/assets/manage/manageBG.png') no-repeat center center;
  146. background-size: cover;
  147. display: flex;
  148. flex-direction: column;
  149. }
  150. .main-content {
  151. flex: 1;
  152. display: flex;
  153. flex-direction: column;
  154. align-items: center;
  155. justify-content: center;
  156. }
  157. .inner-content{
  158. width: 100%;
  159. height: 80%;
  160. display: flex;
  161. justify-content: center;
  162. align-items: center;
  163. gap: rpx(30);
  164. }
  165. .small-box {
  166. width: rpx(180);
  167. height: rpx(230);
  168. background-size: 110%;
  169. background-position: center;
  170. background-repeat: no-repeat;
  171. background-origin: border-box; // 确保背景图从边框开始显示
  172. background-clip: padding-box; // 确保背景图不会延伸到边框外
  173. border-radius: rpx(25);
  174. display: flex;
  175. justify-content: center;
  176. align-items: center;
  177. cursor: pointer;
  178. transition: transform 0.3s ease;
  179. position: relative;
  180. &:hover {
  181. transform: scale(1.05);
  182. box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
  183. }
  184. .box-logout-btn {
  185. position: absolute;
  186. bottom: rpx(0);
  187. right: rpx(0);
  188. padding: rpx(2) rpx(15);
  189. background: linear-gradient(
  190. to right,
  191. #face03,
  192. #fd9f1b
  193. );
  194. border-top-left-radius: rpx(20);
  195. border-bottom-right-radius: rpx(15);
  196. color: white;
  197. font-size: rpx(12);
  198. font-weight: bold;
  199. cursor: pointer;
  200. display: flex;
  201. align-items: center;
  202. gap: rpx(3);
  203. .arrow-icon {
  204. font-size: rpx(14);
  205. }
  206. }
  207. }
  208. .main-content h2 {
  209. color: white;
  210. font-size: rpx(24);
  211. margin-bottom: rpx(60);
  212. text-align: center;
  213. }
  214. .home-buttons {
  215. display: flex;
  216. flex-direction: column;
  217. gap: rpx(20);
  218. width: 100%;
  219. max-width: rpx(400);
  220. }
  221. .home-button {
  222. width: 100%;
  223. height: rpx(60);
  224. font-size: rpx(18);
  225. border-radius: rpx(8);
  226. }
  227. @media (min-width: 768px) {
  228. .home-buttons {
  229. flex-direction: row;
  230. justify-content: center;
  231. flex-wrap: wrap;
  232. }
  233. .home-button {
  234. width: rpx(200);
  235. margin: 0 rpx(10);
  236. }
  237. }
  238. .box-1 {
  239. width: 100%;
  240. min-height: rpx(50);
  241. display: flex;
  242. justify-content: space-between;
  243. align-items: center;
  244. flex-wrap: wrap;
  245. box-sizing: border-box;
  246. font-size: rpx(16);
  247. }
  248. .inner-box {
  249. height: 100%;
  250. display: flex;
  251. justify-content: center;
  252. align-items: center;
  253. font-size: rpx(16);
  254. }
  255. .left-box {
  256. position: relative;
  257. justify-content: flex-start;
  258. align-items: center;
  259. display: flex;
  260. flex: 1;
  261. padding-left: rpx(30);
  262. cursor: pointer;
  263. }
  264. .app-header {
  265. width: 100%;
  266. height: rpx(30);
  267. display: flex;
  268. align-items: center;
  269. gap: rpx(5);
  270. }
  271. .app-logo {
  272. width: rpx(20);
  273. height: rpx(20);
  274. object-fit: contain;
  275. }
  276. .app-header span {
  277. color: white;
  278. font-size: rpx(11);
  279. letter-spacing: rpx(1);
  280. display: flex;
  281. align-items: center;
  282. height: 100%;
  283. margin-right: rpx(10);
  284. max-width: rpx(200);
  285. white-space: normal;
  286. line-height: rpx(16);
  287. text-align: left;
  288. }
  289. .right-box {
  290. flex: 1;
  291. display: flex;
  292. justify-content: flex-end;
  293. align-items: center;
  294. margin-right: rpx(60);
  295. }
  296. .top-right-box {
  297. width: 100%;
  298. display: flex;
  299. justify-content: flex-end;
  300. align-items: center;
  301. flex-wrap: wrap;
  302. cursor: pointer;
  303. }
  304. </style>
  305. <style lang="scss">
  306. /* 只消除非user-name-box的小三角 */
  307. .no-arrow-dropdown .el-popper__arrow{
  308. display: none;
  309. }
  310. .el-popper.is-light,
  311. .el-dropdown__popper.el-popper{
  312. background: transparent;
  313. border: none;
  314. box-shadow: none;
  315. }
  316. .el-dropdown__popper{
  317. --el-dropdown-menuItem-hover-color: none;
  318. }
  319. /* 移除用户名下拉菜单的焦点边框 */
  320. .user-name-box:focus,
  321. .user-name-box:focus-within,
  322. .user-name-box:hover{
  323. outline: none;
  324. box-shadow: none;
  325. }
  326. /* 确保Element Plus下拉菜单触发元素没有焦点边框 */
  327. .el-dropdown .el-dropdown__trigger:focus{
  328. outline: none;
  329. box-shadow: none;
  330. }
  331. </style>