pcHeader.vue 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081
  1. <template>
  2. <header class="desktop-header">
  3. <div class="header-inner">
  4. <div class="header-left">
  5. <div class="brand-wrapper" @click="navigateToRoute('/')">
  6. <icon-svg name="systemLogoCircle" size="40px" />
  7. <div class="brand-text">
  8. <span class="brand-title">环评云助手</span>
  9. </div>
  10. </div>
  11. <nav class="navigation-list" aria-label="顶部导航">
  12. <button v-for="navigationItem in desktopNavigationItems" :key="navigationItem.key" type="button"
  13. class="navigation-item" :class="{ active: isNavigationActive(navigationItem) }"
  14. @click="handleNavigationClick(navigationItem)">
  15. <div class="ai-auto-fill" v-if="navigationItem.key === 'publicPlatform'">
  16. <img src="https://cdntest.eiacloud.com/hpyzs/ai-auto-fill.png">
  17. <span>AI填写</span>
  18. </div>
  19. {{ navigationItem.label }}
  20. </button>
  21. <button
  22. type="button"
  23. class="navigation-item active"
  24. @click="navigateToRoute('/')"
  25. >
  26. MCP服务
  27. </button>
  28. <div class="upload-metrial">
  29. <div class="top-load">
  30. <img src="https://cdntest.eiacloud.com/ai/approval/icons/upload_metrial.png" alt="上传">
  31. <span>资料</span>
  32. </div>
  33. <div class="upload-category">
  34. <ul class="upload-category-wrapper">
  35. <li v-for="uploadMaterialItem in uploadMaterialItems"
  36. :key="uploadMaterialItem.shareType" class="upload-category-li"
  37. @click="handleUploadMaterialClick(uploadMaterialItem.shareType)">
  38. <img :src="uploadMaterialItem.icon" :alt="uploadMaterialItem.label">
  39. <span>{{ uploadMaterialItem.label }}</span>
  40. </li>
  41. </ul>
  42. </div>
  43. </div>
  44. </nav>
  45. </div>
  46. <div class="header-right">
  47. <a class="head-middle-link" :href="orgDomain + '/#/home/control?openVip=1'" target="_blank">
  48. <img src="https://cdntest.eiacloud.com/pc/banner/upgrade_enp_vip_1.png" alt="限时钜惠">
  49. </a>
  50. <div v-for="quickActionItem in quickActionItems" :key="quickActionItem.key" class="quick-action-wrapper"
  51. :class="{ 'has-dropdown': quickActionItem.key === 'client' }">
  52. <button type="button" class="text-action" @click="handleQuickActionClick(quickActionItem)">
  53. <icon-svg v-if="quickActionItem.iconName" :name="quickActionItem.iconName" size="14px" />
  54. <span>{{ quickActionItem.label }}</span>
  55. </button>
  56. <div v-if="quickActionItem.key === 'client'" class="aq-dropdown">
  57. <div class="aq-down-app">
  58. <img src="@/assets/images/siderBar/appInstallPkg.png" alt="APP下载二维码" class="aq-qr-image">
  59. <div class="download-app-contents">
  60. <div class="download-app-text">
  61. <div>扫一扫下载APP</div>
  62. </div>
  63. <a :href="CLIENT_DOWNLOAD_PAGE_URL" target="_blank" rel="noopener noreferrer"
  64. class="gda-btn gda-btn-sm">
  65. <span>手机/电脑端下载</span>
  66. </a>
  67. </div>
  68. </div>
  69. </div>
  70. </div>
  71. <div v-if="isLoggedIn" class="user-panel-wrapper" @mouseleave="hideFeedbackPopover">
  72. <button type="button" class="avatar-button" @click="emit('user-center')">
  73. <img :src="userAvatar" alt="用户头像" class="avatar-image" />
  74. </button>
  75. <div class="user-profile-dropdown">
  76. <div class="user-profile-panel">
  77. <div class="panel-top">
  78. <div class="panel-top-right">
  79. <div class="panel-top-right-primary">
  80. <span class="panel-user-name">{{ userDisplayName }}</span>
  81. <img :src="levelBadgeImg" alt="等级" class="panel-level-badge" />
  82. <span class="panel-vip-badge">
  83. <img :src="vipBadgeImg" alt="会员状态" />
  84. </span>
  85. </div>
  86. <div class="panel-top-right-secondary">
  87. <div class="panel-balance-item">
  88. <img :src="USER_PANEL_ASSETS.yunbeiBadge" alt="云贝" class="panel-status-icon" />
  89. <span>云贝:{{ userYundbeiCount }}</span>
  90. </div>
  91. <div class="panel-balance-item">
  92. <icon-svg name="top_yd" size="16px" class="panel-yundian-icon" />
  93. <span>云点:{{ userYundianCount }}</span>
  94. </div>
  95. </div>
  96. </div>
  97. </div>
  98. <div class="panel-bottom">
  99. <template v-for="menuItem in userProfileMenuItems" :key="menuItem.key">
  100. <el-popover
  101. v-if="menuItem.action === 'feedback'"
  102. ref="feedbackPopoverRef"
  103. placement="left-start"
  104. :width="140"
  105. trigger="hover"
  106. :offset="8"
  107. :teleported="false"
  108. :show-after="120"
  109. :hide-after="80"
  110. popper-class="user-panel-feedback-popover"
  111. >
  112. <template #reference>
  113. <div class="panel-menu-item panel-menu-item-feedback">
  114. <img
  115. :src="menuItem.icon"
  116. :alt="menuItem.label"
  117. class="panel-menu-icon"
  118. />
  119. <span class="panel-menu-text">{{ menuItem.label }}</span>
  120. </div>
  121. </template>
  122. <div class="weChatService">
  123. <img
  124. src="@/assets/images/siderBar/weChatService.png"
  125. alt="微信客服二维码"
  126. />
  127. <span>扫码添加微信客服</span>
  128. </div>
  129. </el-popover>
  130. <button
  131. v-else
  132. type="button"
  133. class="panel-menu-item"
  134. @click="handleUserPanelAction(menuItem)"
  135. >
  136. <img
  137. :src="menuItem.icon"
  138. :alt="menuItem.label"
  139. class="panel-menu-icon"
  140. :class="{ 'panel-menu-icon-upload': menuItem.key === 'upload' }"
  141. />
  142. <span
  143. class="panel-menu-text"
  144. :class="{ 'panel-menu-text-logout': menuItem.key === 'logout' }"
  145. >
  146. {{ menuItem.label }}
  147. <span v-if="menuItem.showDot" class="panel-menu-dot"></span>
  148. </span>
  149. </button>
  150. </template>
  151. </div>
  152. </div>
  153. </div>
  154. </div>
  155. <p class="login-button" v-else @click="$emit('login')">登录 | 注册</p>
  156. </div>
  157. </div>
  158. </header>
  159. </template>
  160. <script setup>
  161. import { computed, ref } from "vue";
  162. import { ElMessage } from "element-plus";
  163. import { useRoute, useRouter } from "vue-router";
  164. import { loginout } from "@/api/login";
  165. import globalStore from "@/store/modules/global";
  166. import { isPcBoolean, orgDomain } from "@/utils/config";
  167. const CLIENT_DOWNLOAD_URL =
  168. "https://www.eiacloud.com/hpy/jx/apk/download.html";
  169. const CLIENT_DOWNLOAD_PAGE_URL = "https://www.eiacloud.com/bbs/download";
  170. const HOME_WEBSITE_URL = "https://www.eiacloud.com/hpyzs/";
  171. const HOME_WEBSITE_LEARN_URL = "https://www.eiacloud.com/hpyzs/academy";
  172. const USER_ORGANIZATION_URL = "https://www.eiacloud.com/hpyzs/center/org";
  173. const USER_CENTER_URL = "https://www.eiacloud.com/hpyzs/center?uri=/center/personalCenter";
  174. const USER_COURSE_URL = "https://www.eiacloud.com/hpyzs/center?uri=/center/academy/course";
  175. const USER_ORDER_URL = "https://www.eiacloud.com/hpyzs/center?uri=/center/academy/order";
  176. const USER_UPLOAD_MATERIAL_URL = "https://www.eiacloud.com/hpyzs/center?uri=/share/myMaterial?ifOpen%3D1";
  177. const USER_API_URL = isPcBoolean
  178. ? "https://orgtest.eiacloud.com/#/home/property?tab=2"
  179. : "https://org.eiacloud.com/#/home/property?tab=2";
  180. const OPEN_PLATFORM_URL = "https://www.eiacloud.com/gs/";
  181. const FORUM_URL = "https://www.eiacloud.com/bbs/";
  182. const SHOP_URL = "https://shop.eiacloud.com/";
  183. const LIVE_URL = "https://www.eiacloud.com/hpyzs/live";
  184. const MAP_URL = "https://www.eiacloud.com/hpyzs/map/stationProjectMap";
  185. const UPLOAD_MATERIAL_BASE_URL = "https://www.eiacloud.com/hpyzs/share/uploadMaterial";
  186. const DEFAULT_USER_NAME = "用户";
  187. const USER_PANEL_ASSETS = Object.freeze({
  188. vipBadge1: "https://www.eiacloud.com/hpyzs/images/2021/vip-0.png",
  189. vipBadge3: "https://www.eiacloud.com/hpyzs/images/2021/vip-1.png",
  190. vipBadge8: "https://www.eiacloud.com/hpyzs/images/2021/vip-2.png",
  191. levelBadge: "https://cdntest.eiacloud.com/ai/personInfo/level/level_",
  192. yunbeiBadge: "https://www.eiacloud.com/hpyzs/images/2021/yunbei.png",
  193. personalCenter: "https://cdntest.eiacloud.com/pc/user/person.png",
  194. collection: "https://cdntest.eiacloud.com/pc/user/collect.png",
  195. organization: "https://cdntest.eiacloud.com/pc/user/orga.png",
  196. course: "https://cdntest.eiacloud.com/pc/user/gongshi.png",
  197. order: "https://cdntest.eiacloud.com/pc/user/order.png",
  198. upload: "https://cdntest.eiacloud.com/pc/share/icon/my-material-upload.png",
  199. api: "https://cdntest.eiacloud.com/pc/user/my-api.png",
  200. feedback: "https://cdntest.eiacloud.com/pc/user/feedback.svg",
  201. logout: "https://cdntest.eiacloud.com/pc/user/exit.png",
  202. });
  203. const props = defineProps({
  204. isLoggedIn: {
  205. type: Boolean,
  206. default: false,
  207. },
  208. userAvatar: {
  209. type: String,
  210. default: "",
  211. },
  212. });
  213. const emit = defineEmits(["login", "user-center"]);
  214. const router = useRouter();
  215. const route = useRoute();
  216. const global = globalStore();
  217. const isLoggingOut = ref(false);
  218. const feedbackPopoverRef = ref(null);
  219. const globalUserInfo = computed(() => global.userInfo ?? {});
  220. const vipBadgeImg = computed(() => USER_PANEL_ASSETS[`vipBadge${globalUserInfo.value?.role || 1}`]);
  221. const levelBadgeImg = computed(() => USER_PANEL_ASSETS.levelBadge + `${globalUserInfo.value?.level || 1}.png`);
  222. const userDisplayName = computed(() => globalUserInfo.value?.showName || globalUserInfo.value?.username || DEFAULT_USER_NAME);
  223. const userYundbeiCount = computed(() => globalUserInfo.value?.yunbeiCount ?? 0);
  224. const userYundianCount = computed(() => {
  225. if (global.yundian != null && global.yundian !== "") return global.yundian;
  226. return globalUserInfo.value?.ydCount ?? 0;
  227. });
  228. const desktopNavigationItems = Object.freeze([
  229. { key: "dialog", label: "首页", type: "external", target: HOME_WEBSITE_URL },
  230. { key: "lanceCloud", label: "监测云", type: "external", target: MAP_URL },
  231. { key: "publicPlatform", label: "公示平台", type: "external", target: OPEN_PLATFORM_URL },
  232. { key: "forum", label: "环评论坛", type: "external", target: FORUM_URL },
  233. { key: "shop", label: "云商城", type: "external", target: SHOP_URL },
  234. { key: "live", label: "直播", type: "external", target: LIVE_URL },
  235. { key: "academy", label: "云学苑", type: "external", target: HOME_WEBSITE_LEARN_URL },
  236. { key: "approveUpload", label: "云助手AI", type: "external", target: "https://ai.eiacloud.com/#/dialog" },
  237. ]);
  238. const quickActionItems = Object.freeze([
  239. { key: "search", label: "搜索", type: "external", target: "https://www.eiacloud.com/hpyzs/lawsRegulations/searchContent", iconName: "historSearch" },
  240. { key: "client", label: "客户端", type: "external", target: CLIENT_DOWNLOAD_URL, iconName: "clientApp" },
  241. ]);
  242. const userProfileMenuItems = computed(() => {
  243. const collectionUrl = "https://www.eiacloud.com/hpyzs/center/myCollection";
  244. const showApiMenu = global.userData?.orgUserType !== 3;
  245. return Object.freeze([
  246. { key: "user-center", label: "个人中心", icon: USER_PANEL_ASSETS.personalCenter, action: "link", target: USER_CENTER_URL },
  247. { key: "collection", label: "我的收藏", icon: USER_PANEL_ASSETS.collection, action: "link", target: collectionUrl },
  248. { key: "organization", label: "企业认证", icon: USER_PANEL_ASSETS.organization, action: "link", target: USER_ORGANIZATION_URL },
  249. { key: "course", label: "我的课程", icon: USER_PANEL_ASSETS.course, action: "link", target: USER_COURSE_URL },
  250. { key: "order", label: "我的订单", icon: USER_PANEL_ASSETS.order, action: "link", target: USER_ORDER_URL },
  251. { key: "upload", label: "我的上传资料", icon: USER_PANEL_ASSETS.upload, action: "link", target: USER_UPLOAD_MATERIAL_URL, showDot: false },
  252. ...(showApiMenu
  253. ? [{ key: "api", label: "我的API", icon: USER_PANEL_ASSETS.api, action: "link", target: USER_API_URL }]
  254. : []),
  255. { key: "feedback", label: "意见反馈", icon: USER_PANEL_ASSETS.feedback, action: "feedback" },
  256. { key: "logout", label: "退出", icon: USER_PANEL_ASSETS.logout, action: "logout" },
  257. ]);
  258. });
  259. const uploadMaterialItems = Object.freeze([
  260. {
  261. shareType: 1,
  262. label: "法律法规规范",
  263. icon: "https://cdntest.eiacloud.com/pc/share/icon/policy.png",
  264. },
  265. {
  266. shareType: 2,
  267. label: "国家或地方标准",
  268. icon: "https://cdntest.eiacloud.com/pc/share/icon/standard.png",
  269. },
  270. {
  271. shareType: 3,
  272. label: "书籍文献资料",
  273. icon: "https://cdntest.eiacloud.com/pc/share/icon/book.png",
  274. },
  275. {
  276. shareType: 4,
  277. label: "报告资料",
  278. icon: "https://cdntest.eiacloud.com/pc/share/icon/law-report.png",
  279. },
  280. {
  281. shareType: 5,
  282. label: "其他类型资料",
  283. icon: "https://cdntest.eiacloud.com/pc/share/icon/other.png",
  284. },
  285. ]);
  286. /**
  287. * 判断当前导航项是否需要高亮。
  288. * MCP 项目由独立 MCP 标签定位,云助手AI 不高亮。
  289. */
  290. const isNavigationActive = () => false;
  291. /**
  292. * 处理顶部导航点击。
  293. * 根据目标类型分发到站内路由或站外页面。
  294. */
  295. const handleNavigationClick = (navigationItem) => {
  296. if (navigationItem.type === "route") {
  297. navigateToRoute(navigationItem.target);
  298. return;
  299. }
  300. openExternalLink(navigationItem.target);
  301. };
  302. /**
  303. * 处理右侧快捷入口点击。
  304. * 保持和主导航一致的跳转逻辑。
  305. */
  306. const handleQuickActionClick = (quickActionItem) => {
  307. if (quickActionItem.type === "route") {
  308. navigateToRoute(quickActionItem.target);
  309. return;
  310. }
  311. openExternalLink(quickActionItem.target);
  312. };
  313. /**
  314. * 处理个人信息面板菜单点击。
  315. * 根据不同动作执行站内跳转、站外打开或退出登录。
  316. */
  317. const hideFeedbackPopover = () => {
  318. feedbackPopoverRef.value?.hide?.();
  319. };
  320. const handleUserPanelAction = async (menuItem) => {
  321. if (menuItem.action === "feedback") {
  322. return;
  323. }
  324. if (menuItem.action === "logout") {
  325. await logoutHandle();
  326. return;
  327. }
  328. openExternalLink(menuItem.target);
  329. };
  330. /**
  331. * 处理资料上传分类点击。
  332. * 根据分类编号拼接上传页参数,并在新窗口打开。
  333. */
  334. const handleUploadMaterialClick = (shareType) => {
  335. openExternalLink(`${UPLOAD_MATERIAL_BASE_URL}?shareType=${shareType}`);
  336. };
  337. /**
  338. * 退出当前登录账号。
  339. * 成功后清理全局登录状态,并跳转登录页。
  340. */
  341. const logoutHandle = async () => {
  342. if (isLoggingOut.value) {
  343. return;
  344. }
  345. isLoggingOut.value = true;
  346. try {
  347. const response = await loginout();
  348. if (response.code === 200) {
  349. ElMessage.success("退出登录成功!");
  350. await global.logout();
  351. router.replace({ name: "login" });
  352. return;
  353. }
  354. ElMessage.error(response.msg || "退出登录失败,请稍后重试");
  355. } catch (error) {
  356. ElMessage.error("退出登录失败,请稍后重试");
  357. } finally {
  358. isLoggingOut.value = false;
  359. }
  360. };
  361. /**
  362. * 跳转到站内页面。
  363. * 已位于目标页时不重复压栈。
  364. */
  365. const navigateToRoute = (targetPath) => {
  366. if (route.path === targetPath) {
  367. return;
  368. }
  369. router.push({
  370. path: targetPath,
  371. });
  372. };
  373. /**
  374. * 打开站外页面。
  375. * 使用新窗口打开,避免打断当前会话。
  376. */
  377. const openExternalLink = (targetUrl) => {
  378. if (typeof window === "undefined" || !targetUrl) {
  379. return;
  380. }
  381. window.open(targetUrl, "_blank", "noopener,noreferrer");
  382. };
  383. </script>
  384. <style scoped lang="less">
  385. .desktop-header {
  386. position: relative;
  387. z-index: 30;
  388. background: #ffffff;
  389. .header-inner {
  390. min-height: 64px;
  391. padding: 0 20px;
  392. display: flex;
  393. align-items: center;
  394. justify-content: space-between;
  395. gap: 0;
  396. }
  397. .header-left {
  398. min-width: 0;
  399. display: flex;
  400. align-items: center;
  401. gap: 20px;
  402. }
  403. .brand-wrapper {
  404. width: auto;
  405. flex-shrink: 0;
  406. display: flex;
  407. align-items: center;
  408. gap: 10px;
  409. cursor: pointer;
  410. }
  411. .brand-logo {
  412. width: 40px;
  413. height: 40px;
  414. object-fit: contain;
  415. }
  416. .brand-text {
  417. display: flex;
  418. align-items: center;
  419. }
  420. .brand-title {
  421. font-weight: 600;
  422. font-size: 28px;
  423. line-height: 1;
  424. color: #1678FF;
  425. letter-spacing: 1px;
  426. }
  427. .navigation-list {
  428. min-width: 0;
  429. display: flex;
  430. align-items: center;
  431. flex-wrap: nowrap;
  432. gap: 0;
  433. }
  434. .upload-metrial {
  435. position: relative;
  436. padding-bottom: 12px;
  437. margin-bottom: -12px;
  438. &:hover {
  439. .upload-category {
  440. opacity: 1;
  441. visibility: visible;
  442. transform: translateY(0);
  443. pointer-events: auto;
  444. }
  445. }
  446. }
  447. .top-load {
  448. height: 36px;
  449. padding: 0 16px;
  450. display: inline-flex;
  451. align-items: center;
  452. justify-content: center;
  453. gap: 4px;
  454. border-radius: 18px;
  455. background: #1678FF;
  456. box-shadow: 0px 2px 6px 0px rgba(66, 133, 244, 0.4);
  457. color: #ffffff;
  458. cursor: pointer;
  459. user-select: none;
  460. img {
  461. width: 18px;
  462. height: 18px;
  463. object-fit: contain;
  464. }
  465. span {
  466. font-size: 15px;
  467. font-weight: 600;
  468. line-height: 20px;
  469. }
  470. }
  471. .upload-category {
  472. position: absolute;
  473. top: calc(100% - 2px);
  474. left: 0;
  475. z-index: 20;
  476. opacity: 0;
  477. visibility: hidden;
  478. transform: translateY(8px);
  479. pointer-events: none;
  480. transition: opacity 0.2s ease, transform 0.2s ease, visibility 0.2s ease;
  481. }
  482. .upload-category-wrapper {
  483. width: 180px;
  484. margin: 0;
  485. padding: 4px 0;
  486. list-style: none;
  487. border-radius: 12px;
  488. background: #ffffff;
  489. box-shadow: 0 12px 30px rgba(31, 52, 88, 0.16);
  490. border: 1px solid #eef2f8;
  491. }
  492. .upload-category-li {
  493. height: 40px;
  494. padding: 0 20px;
  495. display: flex;
  496. align-items: center;
  497. gap: 10px;
  498. cursor: pointer;
  499. transition: background-color 0.2s ease, color 0.2s ease;
  500. &:hover {
  501. background: #f4f8ff;
  502. span {
  503. color: #1678ff;
  504. }
  505. }
  506. img {
  507. width: 20px;
  508. height: 20px;
  509. object-fit: contain;
  510. flex-shrink: 0;
  511. }
  512. span {
  513. font-size: 14px;
  514. line-height: 20px;
  515. color: #333333;
  516. transition: color 0.2s ease;
  517. white-space: nowrap;
  518. }
  519. }
  520. .navigation-item,
  521. .text-action,
  522. .resource-button,
  523. .ai-badge,
  524. .avatar-button {
  525. border: none;
  526. outline: none;
  527. background: transparent;
  528. cursor: pointer;
  529. transition: all 0.2s ease;
  530. }
  531. .navigation-item {
  532. padding: 0;
  533. margin-right: 30px;
  534. font-size: 16px;
  535. line-height: 20px;
  536. color: #333333;
  537. white-space: nowrap;
  538. position: relative;
  539. flex-shrink: 0;
  540. &:hover,
  541. &.active {
  542. color: #1678FF;
  543. }
  544. }
  545. .ai-auto-fill {
  546. position: absolute;
  547. top: -17px;
  548. left: 31px;
  549. background: url(https://cdntest.eiacloud.com/hpyzs/ai-auto-fill-bg.png);
  550. display: flex;
  551. font-size: 12px;
  552. line-height: 16px;
  553. color: #fff;
  554. height: 20px;
  555. background-size: 100% 100%;
  556. font-family: PingFang SC, PingFang SC;
  557. gap: 1px;
  558. width: 56px;
  559. height: 20px;
  560. padding:0 4px 4px 1px;
  561. }
  562. .ai-auto-fill img {
  563. width: 14px;
  564. height: 14px;
  565. margin-top: 1px;
  566. }
  567. .ai-auto-fill span {
  568. line-height: 16px;
  569. }
  570. .header-right {
  571. flex-shrink: 0;
  572. display: flex;
  573. align-items: center;
  574. gap: 20px;
  575. font-weight: 400;
  576. font-size: 16px;
  577. color: #333333;
  578. }
  579. .head-middle-link {
  580. display: inline-flex;
  581. align-items: center;
  582. flex-shrink: 0;
  583. line-height: 0;
  584. img {
  585. height: 54px;
  586. display: block;
  587. object-fit: contain;
  588. }
  589. }
  590. .ai-badge {
  591. height: 24px;
  592. padding: 0 10px;
  593. display: inline-flex;
  594. align-items: center;
  595. justify-content: center;
  596. border-radius: 999px;
  597. background: linear-gradient(90deg, #8c59ff 0%, #cf54ff 100%);
  598. font-size: 12px;
  599. font-weight: 500;
  600. color: #ffffff;
  601. }
  602. .resource-button {
  603. height: 34px;
  604. padding: 0 16px;
  605. display: inline-flex;
  606. align-items: center;
  607. justify-content: center;
  608. border-radius: 18px;
  609. background: linear-gradient(90deg, #2487ff 0%, #1678ff 100%);
  610. box-shadow: 0 6px 16px rgba(22, 120, 255, 0.18);
  611. font-size: 14px;
  612. font-weight: 500;
  613. color: #ffffff;
  614. }
  615. .text-action {
  616. margin-right: 10px;
  617. height: 32px;
  618. padding: 0;
  619. display: inline-flex;
  620. align-items: center;
  621. gap: 6px;
  622. white-space: nowrap;
  623. &:hover {
  624. color: #1678ff;
  625. }
  626. }
  627. .quick-action-wrapper {
  628. position: relative;
  629. display: inline-flex;
  630. align-items: center;
  631. &.has-dropdown {
  632. padding-bottom: 16px;
  633. margin-bottom: -16px;
  634. &:hover {
  635. .aq-dropdown {
  636. opacity: 1;
  637. visibility: visible;
  638. transform: translate(-50%, 0);
  639. pointer-events: auto;
  640. }
  641. }
  642. }
  643. }
  644. .aq-dropdown {
  645. position: absolute;
  646. top: 100%;
  647. left: 50%;
  648. z-index: 40;
  649. padding-top: 8px;
  650. opacity: 0;
  651. visibility: hidden;
  652. transform: translate(-50%, 8px);
  653. pointer-events: none;
  654. transition: opacity 0.2s ease, transform 0.2s ease, visibility 0.2s ease;
  655. }
  656. .aq-down-app {
  657. width: 200px;
  658. padding: 16px;
  659. border-radius: 12px;
  660. background: #ffffff;
  661. box-shadow: 0 12px 30px rgba(31, 52, 88, 0.16);
  662. border: 1px solid #eef2f8;
  663. text-align: center;
  664. }
  665. .aq-qr-image {
  666. width: 160px;
  667. height: 160px;
  668. display: block;
  669. margin: 0 auto;
  670. object-fit: cover;
  671. }
  672. .download-app-contents {
  673. margin-top: 12px;
  674. }
  675. .download-app-text {
  676. margin-bottom: 12px;
  677. font-size: 14px;
  678. line-height: 22px;
  679. font-weight: 600;
  680. color: #4c535c;
  681. }
  682. .gda-btn {
  683. width: 100%;
  684. height: 30px;
  685. display: inline-flex;
  686. align-items: center;
  687. justify-content: center;
  688. border: 1px solid #e8eaec;
  689. background: transparent;
  690. color: #333333;
  691. text-decoration: none;
  692. box-sizing: border-box;
  693. transition: all 0.2s ease;
  694. &:hover {
  695. color: #1678ff;
  696. border-color: #1678ff;
  697. background: #f4f8ff;
  698. }
  699. }
  700. .gda-btn-sm {
  701. font-size: 16px;
  702. line-height: 22px;
  703. }
  704. .avatar-button {
  705. padding: 0;
  706. width: 34px;
  707. height: 34px;
  708. border-radius: 50%;
  709. }
  710. .user-panel-wrapper {
  711. position: relative;
  712. padding-bottom: 12px;
  713. margin-bottom: -12px;
  714. &:hover,
  715. &:focus-within {
  716. .user-profile-dropdown {
  717. opacity: 1;
  718. visibility: visible;
  719. transform: translateY(0);
  720. pointer-events: auto;
  721. }
  722. }
  723. }
  724. .user-profile-dropdown {
  725. position: absolute;
  726. top: calc(100% - 4px);
  727. right: 0;
  728. z-index: 60;
  729. padding-top: 0;
  730. opacity: 0;
  731. visibility: hidden;
  732. transform: translateY(8px);
  733. pointer-events: none;
  734. transition: opacity 0.2s ease, transform 0.2s ease, visibility 0.2s ease;
  735. overflow: visible;
  736. }
  737. .user-profile-panel {
  738. width: 220px;
  739. overflow: visible;
  740. border-radius: 4px;
  741. background: #ffffff;
  742. box-shadow: 0px 16px 32px 0px rgba(0, 0, 0, 0.06);
  743. }
  744. .panel-top {
  745. padding: 21px;
  746. background: url('https://www.eiacloud.com/hpyzs/images/2021/msg-bg.png') no-repeat center center;
  747. background-size: 100% 100%;
  748. }
  749. .panel-top-right {
  750. min-width: 0;
  751. flex: 1;
  752. }
  753. .panel-top-right-primary {
  754. display: flex;
  755. align-items: center;
  756. gap: 4px;
  757. }
  758. .panel-level-badge {
  759. height: 14px;
  760. display: block;
  761. object-fit: contain;
  762. flex-shrink: 0;
  763. }
  764. .panel-user-name {
  765. max-width: 120px;
  766. overflow: hidden;
  767. text-overflow: ellipsis;
  768. white-space: nowrap;
  769. font-weight: 400;
  770. font-size: 14px;
  771. color: #333333;
  772. }
  773. .panel-vip-badge {
  774. line-height: 0;
  775. img {
  776. height: 14px;
  777. display: block;
  778. object-fit: contain;
  779. }
  780. }
  781. .panel-top-right-secondary {
  782. margin-top: 11px;
  783. display: flex;
  784. align-items: center;
  785. justify-content: space-between;
  786. gap: 8px;
  787. font-size: 12px;
  788. color: #757575;
  789. line-height: 14px;
  790. }
  791. .panel-balance-item {
  792. display: flex;
  793. align-items: center;
  794. gap: 4px;
  795. min-width: 0;
  796. white-space: nowrap;
  797. }
  798. .panel-yundian-icon {
  799. flex-shrink: 0;
  800. }
  801. .panel-status-icon {
  802. height: 14px;
  803. display: block;
  804. object-fit: contain;
  805. flex-shrink: 0;
  806. }
  807. .panel-bottom {
  808. padding: 1px;
  809. overflow: visible;
  810. }
  811. .panel-menu-item {
  812. width: 100%;
  813. padding: 0 20px;
  814. border: none;
  815. background: transparent;
  816. display: flex;
  817. align-items: center;
  818. gap: 10px;
  819. height: 40px;
  820. cursor: pointer;
  821. transition: background-color 0.2s ease;
  822. box-sizing: border-box;
  823. &:hover {
  824. background: #f4f8ff;
  825. .panel-menu-text {
  826. color: #1678ff;
  827. }
  828. }
  829. }
  830. .panel-menu-item-feedback {
  831. cursor: default;
  832. }
  833. .panel-menu-icon {
  834. width: 18px;
  835. height: 18px;
  836. display: block;
  837. object-fit: contain;
  838. flex-shrink: 0;
  839. }
  840. .panel-menu-icon-upload {
  841. width: 18px;
  842. height: 18px;
  843. }
  844. .panel-menu-text {
  845. display: inline-flex;
  846. align-items: center;
  847. gap: 6px;
  848. font-size: 14px;
  849. color: #333333;
  850. transition: color 0.2s ease;
  851. }
  852. .panel-menu-text-logout {
  853. color: #757575;
  854. }
  855. .panel-menu-dot {
  856. width: 6px;
  857. height: 6px;
  858. border-radius: 50%;
  859. background: #ff4d4f;
  860. flex-shrink: 0;
  861. }
  862. .avatar-image {
  863. width: 38px;
  864. height: 38px;
  865. display: block;
  866. border-radius: 50%;
  867. object-fit: cover;
  868. border: 1px solid #e8edf5;
  869. }
  870. .login-button {
  871. cursor: pointer;
  872. &:hover {
  873. color: #1678ff;
  874. }
  875. }
  876. }
  877. @media screen and (max-width: 1600px) {
  878. .desktop-header .header-left {
  879. gap: 20px;
  880. }
  881. .desktop-header .navigation-item {
  882. margin-right: 15px;
  883. }
  884. .desktop-header .header-right {
  885. gap: 10px;
  886. }
  887. }
  888. @media screen and (max-width: 1440px) {
  889. .desktop-header {
  890. .header-inner {
  891. padding: 0 20px;
  892. gap: 20px;
  893. }
  894. .header-left {
  895. gap: 20px;
  896. }
  897. .brand-title {
  898. font-size: 24px;
  899. }
  900. .header-right {
  901. gap: 10px;
  902. }
  903. }
  904. }
  905. @media screen and (max-width: 1280px) {
  906. .desktop-header .navigation-list {
  907. display: none;
  908. }
  909. .desktop-header {
  910. .navigation-list {
  911. gap: 0;
  912. }
  913. .navigation-item {
  914. padding: 8px 8px;
  915. font-size: 13px;
  916. }
  917. .text-action {
  918. font-size: 12px;
  919. }
  920. }
  921. }
  922. @media screen and (max-width: 768px) {
  923. .desktop-header .navigation-list {
  924. display: none;
  925. }
  926. .desktop-header .head-middle-link {
  927. display: none;
  928. }
  929. }
  930. </style>
  931. <style lang="less">
  932. .user-panel-feedback-popover {
  933. padding: 12px !important;
  934. min-width: 140px !important;
  935. z-index: 80 !important;
  936. &.el-popper[data-popper-placement^="left"] .el-popper__arrow::before {
  937. border-right-color: #ffffff;
  938. }
  939. .weChatService {
  940. display: flex;
  941. flex-direction: column;
  942. align-items: center;
  943. justify-content: center;
  944. font-weight: 400;
  945. font-size: 12px;
  946. color: #666666;
  947. line-height: 17px;
  948. text-align: center;
  949. img {
  950. width: 120px;
  951. height: 120px;
  952. object-fit: contain;
  953. }
  954. span {
  955. margin-top: 4px;
  956. }
  957. }
  958. }
  959. </style>