铃铛与齿轮两枚图标下线,人像图标成为唯一入口,点击展开一张卡片: 切换身份列表(9条实测溢出滚动)+ 个人信息 + 后台管理(仅管理员)+ 退出登录。 删除无功能损失的冗余入口:原齿轮菜单的 sys/logo/sidebar/statset/backend 五项 已于 2026-09-30 迁入 /settings(Settings.vue:620 ALL_PANES),齿轮成为纯冗余。 消息中心仍走左侧菜单 /msg,LeftMenu 未读角标不受影响。 改动要点: - isUserInfoShow + isRoleInfoShow 合并为 isUserCardShow,9 处函数体同步改名; 删除 onUserinfoClickRoles、storeToRefs import 与 unreadCount 解构(模板已无 Badge) - showUserInfo 改跳 /settings?pane=profile,不再 emit showUserInfoModal (该事件仍有 AppHeader/BschIframe/harness-main 三处消费方,不可删) - :key 用 roleId-schId-childId 复合键,避免同校多身份时 roleId 重复 - header.scss 删 .roleinfo-wrap 与随之失效的 @use "sass:color",新增 .user-card (身份列表 max-height:310px + overflow-y:scroll + 6px 自绘滚动条) - settingsWallpaper 等 6 个入口函数保留:对应 Modal 仍挂模板尾部且 logoList 是 header 徽标数据源,只改内部变量名并加注释 验证:未声明标识符全量扫 47 个 .vue 零问题;vite build 通过;mock 取证实测 scrollHeight 683 > clientHeight 310 出滚动条、1 条时 75=75 不滚动、 menu-rows 管理员 2/普通用户 1、bell-count 与 gear-count 均为 0。 另:.gitignore 忽略卡片取证三件套(本地临时用,与 harness-* 同类不进 git)。
This commit is contained in:
@@ -12,6 +12,13 @@ dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# 视觉取证 harness(本地临时用,不进 git;与 harness-* 同类)
|
||||
.vite-card-harness
|
||||
dist_card_harness
|
||||
card-harness.html
|
||||
card-harness.vite.config.ts
|
||||
src/card-harness-main.ts
|
||||
|
||||
yarn.lock
|
||||
.npmrc
|
||||
# Editor directories and files
|
||||
|
||||
+145
-40
@@ -1,4 +1,3 @@
|
||||
@use "sass:color";
|
||||
.default-header {
|
||||
width: 100%;
|
||||
height: var(--headerH);
|
||||
@@ -220,59 +219,165 @@
|
||||
}
|
||||
}
|
||||
|
||||
.roleinfo-wrap {
|
||||
svg {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
h3.title {
|
||||
height: 50px;
|
||||
padding: 12px 16px;
|
||||
color: #272829;
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
border-bottom: 1px solid #e8eaec;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.roles-ul {
|
||||
max-height: 310px;
|
||||
}
|
||||
.roles-ul li {
|
||||
background-color: #f9f9f9;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 62px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
/* ===== 用户卡片(人像图标唯一入口,2026-10-08)=====
|
||||
规格来源:design/05-Header用户卡片整合-切换身份+个人信息+后台管理+退出登录.html
|
||||
全部复用既有变量,仅新增卡片骨架与滚动条 */
|
||||
.user-card {
|
||||
width: 260px;
|
||||
background: #fff;
|
||||
|
||||
&:hover {
|
||||
// background-color: darken(#f9f9f9, 5%);
|
||||
background-color: color.adjust($color: #f9f9f9, $lightness: -5%);
|
||||
}
|
||||
.user-card-hd {
|
||||
height: 50px;
|
||||
padding: 0 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid #e8eaec;
|
||||
|
||||
svg {
|
||||
margin: 0 16px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
.ttl {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #272829;
|
||||
}
|
||||
.close {
|
||||
margin-left: auto;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 4px;
|
||||
color: #9aa0a8;
|
||||
font-size: 14px;
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
|
||||
&:hover {
|
||||
background: #f2f3f5;
|
||||
color: #5a5f68;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 身份列表:有最大高度,超出显示滚动条 */
|
||||
.user-card-roles {
|
||||
max-height: 310px;
|
||||
overflow-y: scroll;
|
||||
overscroll-behavior: contain;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
&::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: #d4d7dd;
|
||||
border-radius: 3px;
|
||||
}
|
||||
&::-webkit-scrollbar-thumb:hover {
|
||||
background: #b9bec7;
|
||||
}
|
||||
}
|
||||
|
||||
.u-role {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 9px 16px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
transition: background 0.15s;
|
||||
|
||||
> svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-right: 16px;
|
||||
flex: 0 0 16px;
|
||||
}
|
||||
|
||||
.user-wrap {
|
||||
padding: 9px 0;
|
||||
|
||||
.who {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
padding: 8px 0;
|
||||
border-bottom: 1px solid #e9e9e9;
|
||||
flex: auto;
|
||||
.schname-box {
|
||||
|
||||
.nm {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 15px;
|
||||
color: #323233;
|
||||
line-height: 20px;
|
||||
|
||||
.t {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
.sch {
|
||||
margin-top: 2px;
|
||||
font-size: 12px;
|
||||
color: #656667;
|
||||
line-height: 17px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
&:last-child .user-wrap {
|
||||
|
||||
&:last-child .who {
|
||||
border-bottom: none;
|
||||
}
|
||||
&:hover {
|
||||
background: #f9f9f9;
|
||||
}
|
||||
&.active {
|
||||
cursor: default;
|
||||
background: #f9f9f9;
|
||||
|
||||
.nm {
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
.roles-ul li.acitve {
|
||||
cursor: default;
|
||||
background-color: #f9f9f9;
|
||||
|
||||
.user-card-menu {
|
||||
border-top: 1px solid #e9e9e9;
|
||||
|
||||
.arw {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.user-card-logout {
|
||||
padding: 10px 20px 16px;
|
||||
|
||||
.logout-btn {
|
||||
width: 100%;
|
||||
height: 38px;
|
||||
border-radius: 19px;
|
||||
background: #fff;
|
||||
border: 1px solid #e2e5ea;
|
||||
color: #323233;
|
||||
font-size: 14px;
|
||||
font-family: inherit;
|
||||
cursor: pointer;
|
||||
transition: all 0.18s;
|
||||
|
||||
&:hover {
|
||||
border-color: #577afb;
|
||||
background: #f7f9ff;
|
||||
color: #577afb;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+70
-120
@@ -20,110 +20,64 @@
|
||||
</div>
|
||||
</Transition>
|
||||
</li>
|
||||
<!-- 铃铛直跳 /msg(消息对接 2026-09-30:移除 Poptip 浮层与 900 宽列表 Modal,
|
||||
未读数上提 store 与 /msg 页左栏同源;审批直批弹窗抽至 MsgApprovalModal) -->
|
||||
<!-- 人像图标 =唯一入口(2026-10-08整合):铃铛与齿轮两枚图标下线,
|
||||
消息中心仍走左侧菜单 /msg(LeftMenu 保留未读角标);
|
||||
原齿轮菜单的 个人信息/后台管理/退出登陆 合并进本卡片,
|
||||
其余 sys/logo/sidebar/statset 五项 2026-09-30 已迁/settings,不再重复入口 -->
|
||||
<li>
|
||||
<div class="icon-box" v-wave title="消息中心" @click="router.push('/msg')">
|
||||
<Badge :count="unreadCount" :offset="[2, 0]" overflow-count="99">
|
||||
<SvgIcon name="header-2" color="#333333" />
|
||||
</Badge>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<Poptip class="fl" popper-class="roleinfo-wrap reset-panel" :width="240" trigger="click"
|
||||
placement="bottom-end" v-model="isRoleInfoShow" :transfer="true">
|
||||
<div class="icon-box" v-wave>
|
||||
<Poptip class="fl" popper-class="user-card-wrap reset-panel" :width="260" trigger="click"
|
||||
placement="bottom-end" v-model="isUserCardShow" :transfer="true">
|
||||
<div class="icon-box" v-wave title="切换身份">
|
||||
<SvgIcon name="header-3" color="#333333" />
|
||||
</div>
|
||||
<template #content>
|
||||
<h3 class="title">
|
||||
<SvgIcon name="switch-role" color="#272829" />
|
||||
<span class="ml-8">切换身份</span>
|
||||
</h3>
|
||||
<vuescroll>
|
||||
<ul class="roles-ul">
|
||||
<template v-for="(item, index) in userRole">
|
||||
<li :class="{ acitve: getIsCheckRoles(item) }" @click="changeRole(item)">
|
||||
<SvgIcon v-if="getIsCheckRoles(item)" color="#45B972" name="role-checked" />
|
||||
<SvgIcon v-else name="role-check" color="#dcdee0" />
|
||||
<div class="user-wrap">
|
||||
<div class="user-box fix">
|
||||
<span v-if="item.roleId != 3" class="fl f16 mr-10">
|
||||
{{ store.userInfo.name }}
|
||||
</span>
|
||||
<span v-else class="fl f16 mr-10">
|
||||
{{ item.childName }}
|
||||
</span>
|
||||
<span v-if="!!item.roleName" class="role-info">
|
||||
{{ item.roleName }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="schname-box">
|
||||
{{ item.schName }}
|
||||
</div>
|
||||
<div class="user-card">
|
||||
<div class="user-card-hd">
|
||||
<SvgIcon name="switch-role" color="#272829" />
|
||||
<span class="ttl">切换身份</span>
|
||||
<span class="close" @click="isUserCardShow = false">✕</span>
|
||||
</div>
|
||||
<!-- 身份列表有最大高度,超出显示滚动条。
|
||||
key 用 roleId+schId+childId 复合:同校多身份时 roleId 会重复 -->
|
||||
<div class="user-card-roles">
|
||||
<div v-for="item in userRole"
|
||||
:key="`${item.roleId}-${item.schId}-${item.childId}`"
|
||||
:class="['u-role', { active: getIsCheckRoles(item) }]" @click="changeRole(item)">
|
||||
<SvgIcon v-if="getIsCheckRoles(item)" color="#45B972" name="role-checked" />
|
||||
<SvgIcon v-else name="role-check" color="#dcdee0" />
|
||||
<div class="who">
|
||||
<div class="nm">
|
||||
<span class="t">{{ item.roleId != 3 ? store.userInfo.name : item.childName }}</span>
|
||||
<span v-if="!!item.roleName" class="role-info">{{ item.roleName }}</span>
|
||||
</div>
|
||||
</li>
|
||||
</template>
|
||||
<div class="sch">{{ item.schName }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="userinfo-ul user-card-menu">
|
||||
<li @click="showUserInfo">
|
||||
<img :src="requireImg('userinfo/icon1.png')" alt="" />
|
||||
<span>个人信息</span>
|
||||
<svg class="arw" viewBox="0 0 16 16" fill="none">
|
||||
<path
|
||||
d="M6 3.5L10.5 8L6 12.5" stroke="#b6bbc3" stroke-width="1.5"
|
||||
stroke-linecap="round" stroke-linejoin="round" />
|
||||
</svg>
|
||||
</li>
|
||||
<li v-if="!!store.getIsAdmin" @click="linkBackendManage">
|
||||
<SvgIcon name="admin-backend" size="20" color="#323233" class="backend-manage-icon" />
|
||||
<span>后台管理</span>
|
||||
<svg class="arw" viewBox="0 0 16 16" fill="none">
|
||||
<path
|
||||
d="M6 3.5L10.5 8L6 12.5" stroke="#b6bbc3" stroke-width="1.5"
|
||||
stroke-linecap="round" stroke-linejoin="round" />
|
||||
</svg>
|
||||
</li>
|
||||
</ul>
|
||||
</vuescroll>
|
||||
</template>
|
||||
</Poptip>
|
||||
</li>
|
||||
<li>
|
||||
<Poptip class="fl" popper-class="reset-panel" :width="220" trigger="click" placement="bottom-end"
|
||||
v-model="isUserInfoShow" :transfer="true">
|
||||
<div class="icon-box" v-wave>
|
||||
<SvgIcon name="header-5" color="#333333" />
|
||||
</div>
|
||||
<template #content>
|
||||
<ul class="userinfo-ul">
|
||||
<!-- <li class="header border" @click="onUserinfoClickRoles">
|
||||
<span class="name">{{ store.userInfo?.name }}</span>
|
||||
<span v-if="!!store.curRoleInfo?.roleName" class="role-info mr-10">
|
||||
{{ store.curRoleInfo?.roleName }}
|
||||
</span>
|
||||
<Icon :size="18" color="#333" type="ios-arrow-forward" />
|
||||
</li> -->
|
||||
<li class="border" @click="showUserInfo">
|
||||
<img :src="requireImg('userinfo/icon1.png')" alt="" />
|
||||
<span>个人信息</span>
|
||||
</li>
|
||||
<li v-if="!!store.getIsAdmin" @click="linkSysSetting">
|
||||
<img :src="requireImg('userinfo/icon5.png')" alt="" />
|
||||
<span>系统设置</span>
|
||||
</li>
|
||||
<li v-if="!!store.getIsAdmin" @click="linkBackendManage">
|
||||
<SvgIcon name="admin-backend" size="20" color="#323233" class="backend-manage-icon" />
|
||||
<span>后台管理</span>
|
||||
</li>
|
||||
<li v-if="!!store.getIsAdmin" @click="linkLogoSetting">
|
||||
<img :src="requireImg('userinfo/icon3.png')" alt="" />
|
||||
<span>设置LOGO</span>
|
||||
</li>
|
||||
<!-- 边栏设置已迁设置中心(/settings?pane=sidebar,2026-09-30 二轮迁入真实管理),
|
||||
此处仅跳转不再开旧 MenuBarModal(组件保留未挂载) -->
|
||||
<li @click="linkSidebarSetting" v-if="!!store.getIsAdmin">
|
||||
<img :src="requireImg('userinfo/icon6.png')" alt="" />
|
||||
<span>边栏设置</span>
|
||||
</li>
|
||||
<li @click="settingsStats" v-if="!!store.getIsAdmin">
|
||||
<img :src="requireImg('userinfo/icon7.png')" alt="" />
|
||||
<span>统计设置</span>
|
||||
</li>
|
||||
<!--<li @click="settingsTeacherCopilot" v-if="!!store.getIsAdmin">
|
||||
<img :src="requireImg('userinfo/icon8.png')" alt="" />
|
||||
<span>教师助手设置</span>
|
||||
</li>-->
|
||||
|
||||
<li @click="settingsWallpaper" class="border">
|
||||
<img :src="requireImg('userinfo/icon2.png')" alt="" />
|
||||
<span>设置壁纸</span>
|
||||
</li>
|
||||
<li @click="logout">
|
||||
<img :src="requireImg('userinfo/icon4.png')" alt="" />
|
||||
<span>退出登陆</span>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="user-card-logout">
|
||||
<button class="logout-btn" @click="logout">退出登录</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</Poptip>
|
||||
</li>
|
||||
@@ -234,7 +188,6 @@ import SvgIcon from "@/components/SvgIcon.vue";
|
||||
import vuescroll from "vuescroll";
|
||||
import { ref, reactive, computed, onMounted, onUnmounted, inject, watch } from "vue";
|
||||
import { useDefaultStore } from "@/store";
|
||||
import { storeToRefs } from "pinia";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
import { requireImg } from "@/utils/hook/useImg";
|
||||
import ContextMenu from "@/components/ContextMenu.vue";
|
||||
@@ -257,8 +210,8 @@ const refMsgApproval = ref<any>();
|
||||
const { $conf } = useCurrentInstance();
|
||||
const baseUrl = computed(() => $conf.fileHost);
|
||||
|
||||
/** 未读消息数上提 pinia store(消息对接 2026-09-30):Header 角标与 /msg 页左栏、LeftMenu 同源 */
|
||||
const { unreadCount } = storeToRefs(store);
|
||||
/** 未读消息数上提 pinia store(消息对接 2026-09-30):Header 铃铛角标已于 2026-10-08 下线,
|
||||
* 但摘要拉取与 WS 推送仍需保留 —— /msg 页左栏与 LeftMenu 角标与本store 同源 */
|
||||
|
||||
const refSearchInput = ref<any>();
|
||||
const refStatsBarModal = ref<any>();
|
||||
@@ -272,8 +225,7 @@ const logoUrl = computed(() => {
|
||||
const sysLogo = logoList.value.find(x => x.type == 0);
|
||||
return sysLogo ? sysLogo.url : "";
|
||||
});
|
||||
const isUserInfoShow = ref(false),
|
||||
isRoleInfoShow = ref(false),
|
||||
const isUserCardShow = ref(false),
|
||||
isWallpaperShow = ref(false),
|
||||
isLogoShow = ref(false),
|
||||
isSearching = ref(false),
|
||||
@@ -431,7 +383,7 @@ function getIsCheckRoles(item: RoleInfo) {
|
||||
async function changeRole(role: RoleInfo) {
|
||||
if (!!getIsCheckRoles(role)) return;
|
||||
setTimeout(() => {
|
||||
isRoleInfoShow.value = false;
|
||||
isUserCardShow.value = false;
|
||||
}, 150);
|
||||
store.setCurRoleInfo(role);
|
||||
await BaseApi.savUserRole(role);
|
||||
@@ -440,13 +392,6 @@ async function changeRole(role: RoleInfo) {
|
||||
await loadLogoList();
|
||||
}
|
||||
|
||||
function onUserinfoClickRoles() {
|
||||
isUserInfoShow.value = false;
|
||||
setTimeout(() => {
|
||||
isRoleInfoShow.value = true;
|
||||
}, 0);
|
||||
}
|
||||
|
||||
/** 消息类型名(UserMsg msgType:0系统通知/1业务提醒/2审批待办);WS 帧缺 appName 时的降级标签 */
|
||||
function msgTypeLabel(msgType: number | null) {
|
||||
return { 0: "系统通知", 1: "业务提醒", 2: "审批待办" }[msgType as 0 | 1 | 2] || "系统通知";
|
||||
@@ -463,25 +408,28 @@ async function getUserWallpaperList() {
|
||||
// });
|
||||
wallpaperList.value = orderBy(list, ["type", "id"], ["asc", "asc"]);
|
||||
}
|
||||
/** 以下入口函数自2026-10-08 齿轮菜单下线后已无 UI 调用方,但对应 Modal 组件仍挂在模板尾部、
|
||||
* 且 logoList 是header 徽标的数据源,故保留函数体不删,仅把已并轨的 isUserInfoShow 换成 isUserCardShow。
|
||||
* 恢复入口时直接绑到卡片菜单即可。 */
|
||||
async function settingsWallpaper() {
|
||||
await getUserWallpaperList();
|
||||
isUserInfoShow.value = false;
|
||||
isUserCardShow.value = false;
|
||||
isWallpaperShow.value = true;
|
||||
}
|
||||
|
||||
/** 边栏设置入口改跳设置中心 pane(原 settingsMenu 开旧 MenuBarModal 的能力已于 2026-09-30 迁入 Settings.vue sidebar pane) */
|
||||
function linkSidebarSetting() {
|
||||
isUserInfoShow.value = false;
|
||||
isUserCardShow.value = false;
|
||||
router.push("/settings?pane=sidebar");
|
||||
}
|
||||
|
||||
async function settingsStats() {
|
||||
isUserInfoShow.value = false;
|
||||
isUserCardShow.value = false;
|
||||
refStatsBarModal.value.show();
|
||||
}
|
||||
|
||||
async function settingsTeacherCopilot() {
|
||||
isUserInfoShow.value = false;
|
||||
isUserCardShow.value = false;
|
||||
refTeacherCopilotModal.value.show();
|
||||
}
|
||||
|
||||
@@ -523,27 +471,29 @@ async function toggleWidgetShow() {
|
||||
}
|
||||
|
||||
function linkSysSetting() {
|
||||
isUserInfoShow.value = false;
|
||||
isUserCardShow.value = false;
|
||||
router.push("/syssetting");
|
||||
}
|
||||
|
||||
function linkBackendManage() {
|
||||
isUserInfoShow.value = false;
|
||||
isUserCardShow.value = false;
|
||||
const url = `${$conf.baseHost}/userbase/front/index.html`;
|
||||
window.open(url, "_blank");
|
||||
}
|
||||
|
||||
async function linkLogoSetting() {
|
||||
await loadLogoList();
|
||||
isUserInfoShow.value = false;
|
||||
isUserCardShow.value = false;
|
||||
isLogoShow.value = true;
|
||||
}
|
||||
|
||||
function showSeachBox() { }
|
||||
|
||||
/** 卡片菜单:个人信息 → 设置中心 profile pane(与通知端/用户中心同一地址)。
|
||||
* 注意:mittBus 的 showUserInfoModal 事件仍由 AppHeader/BschIframe 使用,此处不再触发 */
|
||||
function showUserInfo() {
|
||||
isUserInfoShow.value = false;
|
||||
mittBus.emit("showUserInfoModal");
|
||||
isUserCardShow.value = false;
|
||||
router.push("/settings?pane=profile");
|
||||
}
|
||||
|
||||
function logout() {
|
||||
|
||||
Reference in New Issue
Block a user