| | |
| | | } |
| | | |
| | | .layout-aside { |
| | | position: relative; |
| | | flex-shrink: 0; |
| | | display: flex; |
| | | flex-direction: column; |
| | | overflow: hidden; |
| | | border-radius: 16px; |
| | | background: linear-gradient(180deg, #16324d 0%, #0d2237 100%); |
| | | box-shadow: 0 14px 32px rgba(22, 50, 77, 0.18); |
| | | transform: translateZ(0); |
| | | backface-visibility: hidden; |
| | | will-change: width; |
| | | transition: width 0.22s cubic-bezier(0.22, 1, 0.36, 1), |
| | | box-shadow 0.22s ease; |
| | | -webkit-user-select: none; |
| | | user-select: none; |
| | | } |
| | | |
| | | .layout-aside.is-animating { |
| | | pointer-events: none; |
| | | } |
| | | |
| | | .layout-panel { |
| | |
| | | background: #f5f7fa; |
| | | box-shadow: 0 14px 32px rgba(83, 104, 129, 0.12); |
| | | border: 1px solid #e4eaf2; |
| | | transform: translateZ(0); |
| | | backface-visibility: hidden; |
| | | } |
| | | |
| | | .aside-logo { |
| | |
| | | box-sizing: border-box; |
| | | color: #fff; |
| | | border-bottom: 1px solid rgba(255, 255, 255, 0.08); |
| | | transition: min-height 0.22s cubic-bezier(0.22, 1, 0.36, 1), |
| | | padding 0.22s cubic-bezier(0.22, 1, 0.36, 1); |
| | | } |
| | | |
| | | .aside-logo-image { |
| | |
| | | max-width: 178px; |
| | | height: auto; |
| | | object-fit: contain; |
| | | transform: translateZ(0); |
| | | transition: max-width 0.22s cubic-bezier(0.22, 1, 0.36, 1); |
| | | } |
| | | |
| | | .aside-logo.is-collapse { |
| | |
| | | box-sizing: border-box; |
| | | } |
| | | |
| | | .aside-fade-enter-active, |
| | | .aside-fade-leave-active { |
| | | transition: opacity 0.14s ease, transform 0.18s ease; |
| | | } |
| | | |
| | | .aside-fade-enter, |
| | | .aside-fade-leave-to { |
| | | opacity: 0; |
| | | transform: translate3d(-10px, 0, 0); |
| | | } |
| | | |
| | | .aside-search .el-input__inner { |
| | | height: 36px; |
| | | line-height: 36px; |
| | | border: 1px solid rgba(255, 255, 255, 0.10); |
| | | background: rgba(255, 255, 255, 0.08); |
| | | color: #fff; |
| | | -webkit-user-select: text; |
| | | user-select: text; |
| | | } |
| | | |
| | | .aside-search .el-input__inner::placeholder { |
| | |
| | | .aside-scroll { |
| | | flex: 1; |
| | | min-height: 0; |
| | | transform: translateZ(0); |
| | | } |
| | | |
| | | .aside-scroll .el-scrollbar__wrap { |
| | |
| | | .side-menu { |
| | | border-right: none; |
| | | background: transparent; |
| | | transform: translateZ(0); |
| | | } |
| | | |
| | | .side-menu .el-submenu__title, |
| | |
| | | margin: 0 10px 6px; |
| | | border-radius: 10px; |
| | | box-sizing: border-box; |
| | | backface-visibility: hidden; |
| | | } |
| | | |
| | | .side-menu .el-submenu__title:hover, |
| | |
| | | background: #fff; |
| | | border-bottom: 1px solid #e8edf5; |
| | | box-sizing: border-box; |
| | | -webkit-user-select: none; |
| | | user-select: none; |
| | | } |
| | | |
| | | .page-tabs { |
| | |
| | | .page-tabs .el-tabs__item { |
| | | height: 38px; |
| | | line-height: 38px; |
| | | -webkit-user-select: none; |
| | | user-select: none; |
| | | } |
| | | |
| | | .tabs-tools { |
| | |
| | | gap: 8px; |
| | | padding-bottom: 6px; |
| | | flex-shrink: 0; |
| | | -webkit-user-select: none; |
| | | user-select: none; |
| | | } |
| | | |
| | | .content-main { |
| | |
| | | word-break: break-word; |
| | | } |
| | | |
| | | @keyframes slideInRight { |
| | | from { |
| | | transform: translate3d(100%, 0, 0); |
| | | opacity: 0; |
| | | } |
| | | |
| | | to { |
| | | transform: translate3d(0, 0, 0); |
| | | opacity: 1; |
| | | } |
| | | } |
| | | |
| | | @keyframes slideOutRight { |
| | | from { |
| | | transform: translate3d(0, 0, 0); |
| | | opacity: 1; |
| | | } |
| | | |
| | | to { |
| | | transform: translate3d(100%, 0, 0); |
| | | opacity: 0; |
| | | } |
| | | } |
| | | |
| | | @keyframes asideSkeletonShimmer { |
| | | 100% { |
| | | transform: translateX(100%); |
| | | } |
| | | } |
| | | |
| | | .ai-drawer-layer { |
| | | box-shadow: -8px 0 24px rgba(0, 0, 0, 0.15) !important; |
| | | border-radius: 8px 0 0 8px !important; |
| | | overflow: hidden; |
| | | animation: slideInRight 0.5s cubic-bezier(0.16, 1, 0.3, 1); |
| | | } |
| | | |
| | | .ai-drawer-layer-close { |
| | | animation: slideOutRight 0.4s cubic-bezier(0.16, 1, 0.3, 1) forwards !important; |
| | | } |
| | | |
| | | .ai-assistant-btn { |
| | |
| | | bottom: 40px; |
| | | z-index: 9999; |
| | | cursor: pointer; |
| | | } |
| | | |
| | | .ai-assistant-mask { |
| | | position: fixed; |
| | | inset: 0; |
| | | z-index: 9997; |
| | | background: rgba(15, 23, 42, 0.10); |
| | | backdrop-filter: blur(3px); |
| | | } |
| | | |
| | | .ai-assistant-drawer { |
| | | position: fixed; |
| | | top: 0; |
| | | right: 0; |
| | | z-index: 9998; |
| | | width: min(600px, 100vw); |
| | | height: 100vh; |
| | | display: flex; |
| | | flex-direction: column; |
| | | background: #fff; |
| | | border-radius: 12px 0 0 12px; |
| | | box-shadow: -10px 0 28px rgba(15, 23, 42, 0.18); |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .ai-drawer-header { |
| | | height: 54px; |
| | | padding: 0 16px 0 20px; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | border-bottom: 1px solid rgba(226, 232, 240, 0.92); |
| | | background: rgba(248, 251, 255, 0.96); |
| | | color: #243447; |
| | | font-size: 15px; |
| | | font-weight: 700; |
| | | box-sizing: border-box; |
| | | } |
| | | |
| | | .ai-drawer-close { |
| | | width: 32px; |
| | | height: 32px; |
| | | border: none; |
| | | border-radius: 10px; |
| | | background: transparent; |
| | | color: #5f7084; |
| | | cursor: pointer; |
| | | font-size: 16px; |
| | | } |
| | | |
| | | .ai-drawer-close:hover { |
| | | background: rgba(236, 243, 249, 0.92); |
| | | color: #24405c; |
| | | } |
| | | |
| | | .ai-drawer-frame { |
| | | flex: 1; |
| | | width: 100%; |
| | | border: none; |
| | | background: #fff; |
| | | } |
| | | |
| | | .ai-mask-enter-active, |
| | | .ai-mask-leave-active { |
| | | transition: opacity .22s ease; |
| | | } |
| | | |
| | | .ai-mask-enter, |
| | | .ai-mask-leave-to { |
| | | opacity: 0; |
| | | } |
| | | |
| | | .ai-panel-enter-active, |
| | | .ai-panel-leave-active { |
| | | transition: transform .28s cubic-bezier(0.22, 1, 0.36, 1), opacity .22s ease; |
| | | } |
| | | |
| | | .ai-panel-enter, |
| | | .ai-panel-leave-to { |
| | | transform: translate3d(100%, 0, 0); |
| | | opacity: 0; |
| | | } |
| | | |
| | | @media (max-width: 1440px) { |
| | |
| | | <body> |
| | | <div id="app" v-cloak> |
| | | <el-container class="shell-container"> |
| | | <el-aside class="layout-aside" :width="asideWidth"> |
| | | <div class="aside-logo" :class="{ 'is-collapse': isCollapse }"> |
| | | <el-aside |
| | | class="layout-aside" |
| | | :class="{ 'is-animating': collapseAnimating }" |
| | | :width="asideWidth"> |
| | | <div class="aside-logo" :class="{ 'is-collapse': asideCompact }"> |
| | | <img class="aside-logo-image" src="../static/images/zy-logo.png" alt="浙江中扬"> |
| | | </div> |
| | | |
| | | <div class="aside-search" v-show="!isCollapse"> |
| | | <el-input |
| | | v-model.trim="menuKeyword" |
| | | size="small" |
| | | clearable |
| | | prefix-icon="el-icon-search" |
| | | :placeholder="t('index.searchMenu')"> |
| | | </el-input> |
| | | </div> |
| | | <transition name="aside-fade"> |
| | | <div class="aside-search" v-show="showAsideExtras"> |
| | | <el-input |
| | | v-model.trim="menuKeyword" |
| | | size="small" |
| | | clearable |
| | | prefix-icon="el-icon-search" |
| | | :placeholder="t('index.searchMenu')"> |
| | | </el-input> |
| | | </div> |
| | | </transition> |
| | | |
| | | <el-scrollbar class="aside-scroll"> |
| | | <div v-if="menuLoading" class="aside-loading" aria-hidden="true"> |
| | |
| | | ref="sideMenu" |
| | | class="side-menu" |
| | | :default-active="activeMenuKey" |
| | | :collapse="isCollapse" |
| | | :collapse="menuCollapse" |
| | | :collapse-transition="false" |
| | | :default-openeds="defaultOpeneds" |
| | | unique-opened |
| | |
| | | </template> |
| | | </el-scrollbar> |
| | | |
| | | <div class="aside-footer" v-show="!isCollapse"> |
| | | <div class="aside-footer-copy">© 2026 {{ t('app.company') }}</div> |
| | | <div class="aside-footer-version"> |
| | | <span class="aside-footer-version-text">{{ versionText }}</span> |
| | | <el-tag |
| | | v-if="versionType" |
| | | size="mini" |
| | | :type="versionTagType" |
| | | effect="dark"> |
| | | {{ versionTypeTag }} |
| | | </el-tag> |
| | | <transition name="aside-fade"> |
| | | <div class="aside-footer" v-show="showAsideExtras"> |
| | | <div class="aside-footer-copy">© 2026 {{ t('app.company') }}</div> |
| | | <div class="aside-footer-version"> |
| | | <span class="aside-footer-version-text">{{ versionText }}</span> |
| | | <el-tag |
| | | v-if="versionType" |
| | | size="mini" |
| | | :type="versionTagType" |
| | | effect="dark"> |
| | | {{ versionTypeTag }} |
| | | </el-tag> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </transition> |
| | | </el-aside> |
| | | |
| | | <el-container class="layout-panel"> |
| | |
| | | </span> |
| | | </el-dialog> |
| | | |
| | | <div |
| | | id="ai-assistant-btn" |
| | | class="ai-assistant-btn" |
| | | @mouseenter="showAiTip" |
| | | @mouseleave="hideAiTip" |
| | | @click="openAiAssistant"> |
| | | </div> |
| | | <el-tooltip :content="t('common.aiAssistant')" placement="left"> |
| | | <div |
| | | id="ai-assistant-btn" |
| | | class="ai-assistant-btn" |
| | | @click="openAiAssistant"> |
| | | </div> |
| | | </el-tooltip> |
| | | |
| | | <transition name="ai-mask"> |
| | | <div |
| | | v-if="aiAssistantVisible" |
| | | class="ai-assistant-mask" |
| | | @click="closeAiAssistant"> |
| | | </div> |
| | | </transition> |
| | | |
| | | <transition name="ai-panel"> |
| | | <div |
| | | v-if="aiAssistantVisible" |
| | | class="ai-assistant-drawer"> |
| | | <div class="ai-drawer-header"> |
| | | <span>{{ t('common.aiAssistant') }}</span> |
| | | <button type="button" class="ai-drawer-close" @click="closeAiAssistant"> |
| | | <i class="el-icon-close"></i> |
| | | </button> |
| | | </div> |
| | | <iframe |
| | | v-if="aiAssistantMounted" |
| | | class="ai-drawer-frame" |
| | | :src="aiAssistantSrc"> |
| | | </iframe> |
| | | </div> |
| | | </transition> |
| | | </div> |
| | | |
| | | <script type="text/javascript" src="../static/js/jquery/jquery-3.3.1.min.js"></script> |
| | | <script type="text/javascript" src="../static/js/layer/layer.js"></script> |
| | | <script type="text/javascript" src="../static/js/common.js?v=20260309_i18n_fix1"></script> |
| | | <script type="text/javascript" src="../static/js/common.js"></script> |
| | | <script type="text/javascript" src="../static/vue/js/vue.min.js"></script> |
| | | <script type="text/javascript" src="../static/vue/element/element.js"></script> |
| | | <script> |
| | |
| | | group: "账户中心", |
| | | menuKey: "" |
| | | }; |
| | | var SIDEBAR_TRANSITION_MS = 220; |
| | | var SIDEBAR_EXPAND_CONTENT_DELAY = 180; |
| | | var TAB_STORAGE_KEY = "wcs-element-home-tabs"; |
| | | var USER_STORAGE_KEY = "username"; |
| | | var INDEX_I18N_FALLBACKS = { |
| | |
| | | data: function () { |
| | | return { |
| | | isCollapse: false, |
| | | asideCompact: false, |
| | | menuCollapse: false, |
| | | showAsideExtras: true, |
| | | collapseAnimating: false, |
| | | collapseTimer: null, |
| | | menuLoading: true, |
| | | pageLoading: true, |
| | | loadingText: window.WCS_I18N ? window.WCS_I18N.tl("正在加载页面...") : "正在加载页面...", |
| | |
| | | menuSyncVersion: 0, |
| | | menuSyncTimer: null, |
| | | userName: localStorage.getItem(USER_STORAGE_KEY) || (window.WCS_I18N ? window.WCS_I18N.tl("管理员") : "管理员"), |
| | | aiLayerIndex: null, |
| | | aiTipIndex: null |
| | | aiAssistantVisible: false, |
| | | aiAssistantMounted: false, |
| | | aiAssistantSrc: baseUrl + "/views/ai/diagnosis.html" |
| | | }; |
| | | }, |
| | | computed: { |
| | | asideWidth: function () { |
| | | return this.isCollapse ? "72px" : "248px"; |
| | | return this.asideCompact ? "72px" : "248px"; |
| | | }, |
| | | filteredMenus: function () { |
| | | var keyword = (this.menuKeyword || "").toLowerCase(); |
| | |
| | | clearTimeout(this.menuSyncTimer); |
| | | this.menuSyncTimer = null; |
| | | } |
| | | if (this.aiTipIndex) { |
| | | layer.close(this.aiTipIndex); |
| | | this.aiTipIndex = null; |
| | | if (this.collapseTimer) { |
| | | clearTimeout(this.collapseTimer); |
| | | this.collapseTimer = null; |
| | | } |
| | | }, |
| | | methods: { |
| | |
| | | PROFILE_TAB_CONFIG.title = profileConfig.title; |
| | | PROFILE_TAB_CONFIG.group = profileConfig.group; |
| | | for (i = 0; i < this.tabs.length; i++) { |
| | | if (this.isHomeTabUrl(this.tabs[i].url)) { |
| | | this.tabs[i].title = homeConfig.title; |
| | | this.tabs[i].group = homeConfig.group; |
| | | this.tabs[i].home = true; |
| | | } else if (this.resolveViewSrc(this.tabs[i].url) === this.resolveViewSrc(profileConfig.url)) { |
| | | this.tabs[i].title = profileConfig.title; |
| | | this.tabs[i].group = profileConfig.group; |
| | | } else { |
| | | this.tabs[i].title = this.translateTabTitle(this.tabs[i].title); |
| | | this.tabs[i].group = this.tl(this.tabs[i].group); |
| | | } |
| | | this.syncTabMeta(this.tabs[i], homeConfig, profileConfig); |
| | | } |
| | | this.updateDocumentTitle(this.activeTabTitle); |
| | | this.persistTabs(); |
| | |
| | | }, |
| | | translateTabTitle: function (title) { |
| | | return this.tl(title); |
| | | }, |
| | | findMenuMeta: function (tab) { |
| | | var normalizedUrl; |
| | | var i; |
| | | var j; |
| | | var group; |
| | | var item; |
| | | if (!tab) { |
| | | return null; |
| | | } |
| | | normalizedUrl = this.resolveViewSrc(tab.url); |
| | | for (i = 0; i < this.menus.length; i++) { |
| | | group = this.menus[i]; |
| | | for (j = 0; j < group.subMenu.length; j++) { |
| | | item = group.subMenu[j]; |
| | | if ((tab.menuKey && item.tabKey === tab.menuKey) || item.url === normalizedUrl) { |
| | | return { |
| | | group: group, |
| | | item: item |
| | | }; |
| | | } |
| | | } |
| | | } |
| | | return null; |
| | | }, |
| | | syncTabMeta: function (tab, homeConfig, profileConfig) { |
| | | var menuMeta; |
| | | if (!tab) { |
| | | return; |
| | | } |
| | | if (this.isHomeTabUrl(tab.url)) { |
| | | tab.title = homeConfig.title; |
| | | tab.group = homeConfig.group; |
| | | tab.home = true; |
| | | return; |
| | | } |
| | | if (this.resolveViewSrc(tab.url) === this.resolveViewSrc(profileConfig.url)) { |
| | | tab.title = profileConfig.title; |
| | | tab.group = profileConfig.group; |
| | | return; |
| | | } |
| | | menuMeta = this.findMenuMeta(tab); |
| | | if (menuMeta) { |
| | | tab.title = menuMeta.item.name; |
| | | tab.group = menuMeta.group.menu; |
| | | tab.menuKey = menuMeta.item.tabKey || tab.menuKey; |
| | | return; |
| | | } |
| | | tab.title = this.translateTabTitle(tab.title); |
| | | tab.group = this.tl(tab.group); |
| | | }, |
| | | updateDocumentTitle: function (title) { |
| | | document.title = title + " - " + this.t("app.title"); |
| | |
| | | script = frameDocument.createElement("script"); |
| | | script.id = "wcs-i18n-bridge-script"; |
| | | script.type = "text/javascript"; |
| | | script.src = baseUrl + "/static/js/common.js?v=20260309_i18n_fix1"; |
| | | script.src = baseUrl + "/static/js/common.js"; |
| | | script.onload = applyFrameI18n; |
| | | frameDocument.head.appendChild(script); |
| | | }, |
| | |
| | | this.syncFrameI18n(this.tabs[i].name); |
| | | } |
| | | }, |
| | | clearCollapseTimer: function () { |
| | | if (this.collapseTimer) { |
| | | clearTimeout(this.collapseTimer); |
| | | this.collapseTimer = null; |
| | | } |
| | | }, |
| | | nextFrame: function (callback) { |
| | | if (window.requestAnimationFrame) { |
| | | window.requestAnimationFrame(function () { |
| | | callback(); |
| | | }); |
| | | return; |
| | | } |
| | | setTimeout(callback, 16); |
| | | }, |
| | | finishCollapseStage: function (callback, delay) { |
| | | var that = this; |
| | | this.clearCollapseTimer(); |
| | | this.collapseTimer = setTimeout(function () { |
| | | that.collapseTimer = null; |
| | | callback(); |
| | | }, delay); |
| | | }, |
| | | toggleCollapse: function () { |
| | | this.isCollapse = !this.isCollapse; |
| | | var that = this; |
| | | |
| | | if (this.collapseAnimating) { |
| | | return; |
| | | } |
| | | |
| | | this.collapseAnimating = true; |
| | | |
| | | if (this.isCollapse) { |
| | | this.isCollapse = false; |
| | | this.asideCompact = false; |
| | | this.nextFrame(function () { |
| | | that.finishCollapseStage(function () { |
| | | that.menuCollapse = false; |
| | | that.showAsideExtras = true; |
| | | that.collapseAnimating = false; |
| | | that.$nextTick(function () { |
| | | that.syncMenuStateByUrl(that.activeTabUrl); |
| | | }); |
| | | }, SIDEBAR_EXPAND_CONTENT_DELAY); |
| | | }); |
| | | return; |
| | | } |
| | | |
| | | this.isCollapse = true; |
| | | this.showAsideExtras = false; |
| | | this.menuCollapse = true; |
| | | this.$nextTick(function () { |
| | | that.nextFrame(function () { |
| | | that.asideCompact = true; |
| | | that.finishCollapseStage(function () { |
| | | that.collapseAnimating = false; |
| | | }, SIDEBAR_TRANSITION_MS); |
| | | }); |
| | | }); |
| | | }, |
| | | handleMenuSelect: function (group, item) { |
| | | this.addOrActivateTab({ |
| | |
| | | if (!menu) { |
| | | return; |
| | | } |
| | | if (that.menuCollapse) { |
| | | return; |
| | | } |
| | | openedMenus = menu.openedMenus ? menu.openedMenus.slice() : []; |
| | | if (!groupIndex) { |
| | | if (openedMenus.length) { |
| | |
| | | that.menuLoading = false; |
| | | if (res.code === 200) { |
| | | that.menus = that.normalizeMenuData(res.data || []); |
| | | that.refreshI18nState(); |
| | | that.syncMenuStateByUrl(that.activeTabUrl); |
| | | } else if (res.code === 403) { |
| | | top.location.href = baseUrl + "/login"; |
| | |
| | | document.exitFullscreen(); |
| | | } |
| | | }, |
| | | showAiTip: function () { |
| | | this.hideAiTip(); |
| | | this.aiTipIndex = layer.tips(this.t("common.aiAssistant"), "#ai-assistant-btn", { |
| | | tips: [1, "#333"], |
| | | time: -1 |
| | | }); |
| | | }, |
| | | hideAiTip: function () { |
| | | if (this.aiTipIndex) { |
| | | layer.close(this.aiTipIndex); |
| | | this.aiTipIndex = null; |
| | | } |
| | | }, |
| | | openAiAssistant: function () { |
| | | var that = this; |
| | | var $layero; |
| | | var $shade; |
| | | |
| | | this.hideAiTip(); |
| | | |
| | | if (this.aiLayerIndex !== null && $("#layui-layer" + this.aiLayerIndex).length > 0) { |
| | | $layero = $("#layui-layer" + this.aiLayerIndex); |
| | | $shade = $("#layui-layer-shade" + this.aiLayerIndex); |
| | | |
| | | $shade.show().css("opacity", 0.1); |
| | | $layero.show(); |
| | | $layero.removeClass("ai-drawer-layer-close"); |
| | | $layero.removeClass("ai-drawer-layer"); |
| | | void $layero.get(0).offsetWidth; |
| | | $layero.addClass("ai-drawer-layer"); |
| | | return; |
| | | if (!this.aiAssistantMounted) { |
| | | this.aiAssistantMounted = true; |
| | | } |
| | | |
| | | layer.open({ |
| | | type: 2, |
| | | title: false, |
| | | closeBtn: 0, |
| | | shadeClose: false, |
| | | shade: 0.1, |
| | | area: ["600px", "100%"], |
| | | offset: "r", |
| | | anim: -1, |
| | | isOutAnim: false, |
| | | skin: "ai-drawer-layer", |
| | | content: "ai/diagnosis.html", |
| | | success: function (layero, index) { |
| | | var shadeId; |
| | | var $shadeEl; |
| | | |
| | | that.aiLayerIndex = index; |
| | | shadeId = layero.attr("id").replace("layui-layer", "layui-layer-shade"); |
| | | $shadeEl = $("#" + shadeId); |
| | | $shadeEl.css({ |
| | | "backdrop-filter": "blur(3px)", |
| | | transition: "opacity 0.8s" |
| | | }); |
| | | $shadeEl.off("click.aiAssistant").on("click.aiAssistant", function () { |
| | | layero.addClass("ai-drawer-layer-close"); |
| | | $shadeEl.css("opacity", 0); |
| | | setTimeout(function () { |
| | | layero.hide(); |
| | | $shadeEl.hide(); |
| | | }, 400); |
| | | }); |
| | | } |
| | | }); |
| | | this.aiAssistantVisible = true; |
| | | }, |
| | | closeAiAssistant: function () { |
| | | this.aiAssistantVisible = false; |
| | | }, |
| | | handleUserCommand: function (command) { |
| | | if (command === "profile") { |