Browse Source

feat:修改全局左侧菜单样式、修改组件sssubtab组件样式

apple 2 days ago
parent
commit
49e94eacd5

+ 494 - 0
SsSubTab组件改造方案.md

@@ -0,0 +1,494 @@
+# SsSubTab 组件改造方案
+
+## 文件位置
+`/js/vue/ss-components.js` 第 5715-5895 行
+
+## 改造目标
+
+### 1. UI 模式改造
+- **去掉**:顶部图片 `headerImage`
+- **新增两种模式**:
+  - `collapse`(默认):只显示图标,鼠标悬停时浮动显示文字
+  - `fixed`:只显示图标,不展开浮动
+
+### 2. 性能优化
+- **现状**:iframe 用 `v-show`,页面打开时全部加载
+- **改为**:懒加载,点击哪个才加载哪个
+
+---
+
+## 具体修改方案
+
+### 一、Props 修改
+
+```js
+// 删除
+headerImage: { type: String, default: "" },
+
+// 新增
+initialMode: {
+  type: String,
+  default: 'collapse',  // 'collapse' | 'fixed'
+  validator: (v) => ['collapse', 'fixed'].includes(v)
+},
+```
+
+### 二、Setup 新增逻辑
+
+```js
+setup(props, { emit }) {
+  // ... 原有逻辑保留 ...
+
+  // ===== 新增:菜单模式管理 =====
+  const menuMode = ref(props.initialMode); // 'collapse' | 'fixed'
+  const isHovering = ref(false);  // 鼠标是否在菜单区域
+
+  // 切换模式
+  const toggleMenuMode = () => {
+    menuMode.value = menuMode.value === 'collapse' ? 'fixed' : 'collapse';
+  };
+
+  // 鼠标进入/离开
+  const onMouseEnter = () => {
+    if (menuMode.value === 'collapse') {
+      isHovering.value = true;
+    }
+  };
+  const onMouseLeave = () => {
+    isHovering.value = false;
+  };
+
+  // 是否显示文字(展开状态)
+  const isExpanded = computed(() => {
+    return menuMode.value === 'collapse' && isHovering.value;
+  });
+
+  // ===== 新增:iframe 懒加载 =====
+  const loadedMenus = ref(new Set());  // 已加载过的菜单 name
+
+  // 修改 selectItem
+  const selectItem = (item) => {
+    currentMenu.value = item;
+    // 标记为已加载
+    if (item.name) {
+      loadedMenus.value.add(item.name);
+    }
+    emit("menu-change", item);
+  };
+
+  // 初始化:默认选中项需要加入已加载集合
+  watch(currentMenu, (menu) => {
+    if (menu?.name) {
+      loadedMenus.value.add(menu.name);
+    }
+  }, { immediate: true });
+
+  // 判断菜单是否已加载
+  const isMenuLoaded = (menuName) => {
+    return loadedMenus.value.has(menuName);
+  };
+
+  return {
+    // 原有
+    currentMenu,
+    selectItem,
+    handleFooterClick,
+    // 新增
+    menuMode,
+    isHovering,
+    isExpanded,
+    toggleMenuMode,
+    onMouseEnter,
+    onMouseLeave,
+    isMenuLoaded,
+  };
+}
+```
+
+### 三、Template 修改
+
+```html
+<div class="project-edit-container">
+    <!-- 左侧菜单 -->
+    <div class="left-side"
+         v-if="leftDisplay"
+         :data-mode="menuMode"
+         :class="{ 'is-expanded': isExpanded }"
+         @mouseenter="onMouseEnter"
+         @mouseleave="onMouseLeave">
+
+        <!-- 删除:头部图片 -->
+
+        <!-- 菜单内容 -->
+        <div class="menu-content">
+            <div class="scroll-view">
+                <template v-for="(menuItem, i) in menuList" :key="i">
+
+                    <!-- 分组菜单 -->
+                    <div v-if="menuItem.children?.length > 0" class="group">
+                        <div class="menu-item" @click="menuItem.open = !menuItem.open">
+                            <ss-icon :name="menuItem.icon || 'folder'" class="menu-icon" size="20px" />
+                            <span class="menu-label" v-show="isExpanded">{{ menuItem.title }}</span>
+                            <span class="arrow" v-show="isExpanded">
+                                <ss-icon :name="menuItem.open ? 'arrow-up' : 'arrow-down'" size="16px" />
+                            </span>
+                            <!-- 收起时的悬浮提示 -->
+                            <div class="menu-tooltip" v-show="!isExpanded">{{ menuItem.title }}</div>
+                        </div>
+                        <div v-show="menuItem.open && isExpanded" class="group-detail">
+                            <div v-for="(item, j) in menuItem.children"
+                                :key="j"
+                                class="menu-item"
+                                :class="{ active: item.name === currentMenu?.name }"
+                                @click="selectItem(item)">
+                                <ss-icon :name="item.icon || 'file'" class="menu-icon" size="18px" />
+                                <span class="menu-label">{{ item.title }}</span>
+                                <span class="menu-item-point" v-if="item.cgxList || item.objectList"></span>
+                            </div>
+                        </div>
+                    </div>
+
+                    <!-- 普通菜单项 -->
+                    <div v-else
+                        class="menu-item"
+                        :class="{ active: menuItem.name === currentMenu?.name }"
+                        @click="selectItem(menuItem)">
+                        <ss-icon :name="menuItem.icon || 'file'" class="menu-icon" size="20px" />
+                        <span class="menu-label" v-show="isExpanded">{{ menuItem.title }}</span>
+                        <span class="menu-item-point" v-if="menuItem.cgxList || menuItem.objectList"></span>
+                        <!-- 收起时的悬浮提示 -->
+                        <div class="menu-tooltip" v-show="!isExpanded">{{ menuItem.title }}</div>
+                    </div>
+
+                </template>
+            </div>
+        </div>
+
+        <!-- 底部:模式切换按钮 -->
+        <div class="menu-mode-toggle" @click="toggleMenuMode">
+            <ss-icon :name="menuMode === 'collapse' ? 'pin' : 'pin-fill'" size="20px" />
+            <span class="menu-label" v-show="isExpanded">
+                {{ menuMode === 'collapse' ? '固定菜单' : '取消固定' }}
+            </span>
+        </div>
+
+        <!-- 底部按钮(保留原有) -->
+        <div v-if="footerButtons.length > 0" class="sub-tab-menu-footer" @click="footerButtons[0].onclick">
+            <!-- ... 保持原有 ... -->
+        </div>
+
+    </div>
+
+    <!-- 右侧内容区域 - 懒加载 iframe -->
+    <div class="content-area fit-height-content"
+         style="overflow: hidden;"
+         :style="!leftDisplay ? { width: '100%' } : {}">
+
+        <template v-for="(menuItem, i) in menuList" :key="i">
+            <!-- 只有加载过的才渲染 iframe -->
+            <iframe
+                v-if="isMenuLoaded(menuItem.name)"
+                :src="menuItem.url"
+                style="height: 100%;width: 100%;"
+                frameborder="0"
+                class="sub-tab-iframe"
+                :id="i === 0 ? 'sub-tab-iframe' : ''"
+                v-show="currentMenu?.name === menuItem.name"
+            />
+        </template>
+
+    </div>
+</div>
+```
+
+---
+
+## CSS 样式修改(base.css:4784-4968)
+
+### 现有样式分析
+```css
+/* 现有:固定 180px 宽度 */
+.project-edit-container .left-side {
+  width: 180px !important;  /* 需要改为动态 */
+}
+.project-edit-container>div.content-area {
+  width: calc(100% - 180px);  /* 需要改为动态 */
+}
+```
+
+### 需要修改的样式
+
+#### 1. 左侧容器宽度(行 4798-4802)
+```css
+/* 原来 */
+.project-edit-container .left-side {
+  width: 180px !important;
+  border-right: 1px solid #e2e4ec;
+  background-color: #edf1f5;
+}
+
+/* 改为 */
+.project-edit-container .left-side {
+  width: 60px;  /* 默认收起宽度 */
+  border-right: 1px solid #e2e4ec;
+  background-color: #edf1f5;
+  transition: width 0.2s ease;
+  display: flex;
+  flex-direction: column;
+  overflow: hidden;
+}
+
+/* 展开状态 */
+.project-edit-container .left-side.is-expanded {
+  width: 200px;
+}
+
+/* 固定模式:始终收起,不响应悬浮 */
+.project-edit-container .left-side[data-mode="fixed"] {
+  width: 60px !important;
+}
+```
+
+#### 2. 右侧内容区宽度(行 4964-4967)
+```css
+/* 原来 */
+.project-edit-container>div.content-area {
+  width: calc(100% - 180px);
+  overflow-y: auto;
+}
+
+/* 改为 */
+.project-edit-container>div.content-area {
+  flex: 1;  /* 自动填充剩余空间 */
+  overflow-y: auto;
+}
+```
+
+#### 3. 菜单项样式(行 4824-4832)
+```css
+/* 原来 */
+.project-edit-container .menu-item,
+.project-edit-container .group .menu-item {
+  padding: 20px 12px 20px 30px;
+  cursor: pointer;
+  position: relative;
+  color: #333333;
+  display: flex;
+  align-items: center;
+}
+
+/* 改为 */
+.project-edit-container .menu-item,
+.project-edit-container .group .menu-item {
+  padding: 15px;
+  cursor: pointer;
+  position: relative;
+  color: #333333;
+  display: flex;
+  align-items: center;
+  justify-content: center;  /* 收起时图标居中 */
+  gap: 10px;
+}
+
+/* 展开时左对齐 */
+.project-edit-container .left-side.is-expanded .menu-item {
+  justify-content: flex-start;
+  padding: 15px 20px;
+}
+```
+
+#### 4. 删除头部图片相关样式(行 4808-4815)
+```css
+/* 删除或注释掉 */
+/* .project-edit-container .menu-header {
+  height: 120px;
+  border-bottom: 1px solid #d8dae3;
+} */
+
+/* 修改 menu-content 高度 */
+.project-edit-container .menu-content {
+  height: calc(100% - 50px);  /* 原来是 calc(100% - 60px),去掉图片后调整 */
+  flex: 1;
+  overflow: hidden;
+}
+```
+
+#### 5. 箭头位置(行 4834-4837)
+```css
+/* 原来:固定位置 */
+.project-edit-container .menu-item .arrow {
+  position: absolute;
+  left: 180px;
+}
+
+/* 改为:相对定位,放在右侧 */
+.project-edit-container .menu-item .arrow {
+  margin-left: auto;
+}
+```
+
+### 需要新增的样式
+
+```css
+/* ===== 新增:图标样式 ===== */
+.project-edit-container .menu-icon {
+  flex-shrink: 0;
+  width: 24px;
+  height: 24px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+/* ===== 新增:文字标签 ===== */
+.project-edit-container .menu-label {
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
+}
+
+/* 收起时隐藏文字 */
+.project-edit-container .left-side:not(.is-expanded) .menu-label {
+  display: none;
+}
+
+/* ===== 新增:悬浮提示(收起时显示) ===== */
+.project-edit-container .menu-tooltip {
+  position: absolute;
+  left: calc(100% + 10px);
+  top: 50%;
+  transform: translateY(-50%);
+  background: #393d51;
+  color: #fff;
+  padding: 8px 16px;
+  border-radius: 4px;
+  white-space: nowrap;
+  z-index: 1000;
+  opacity: 0;
+  pointer-events: none;
+  transition: opacity 0.15s ease;
+  font-size: 14px;
+}
+
+/* 小三角 */
+.project-edit-container .menu-tooltip::before {
+  content: "";
+  position: absolute;
+  left: -6px;
+  top: 50%;
+  transform: translateY(-50%);
+  border: 6px solid transparent;
+  border-right-color: #393d51;
+  border-left: none;
+}
+
+/* 悬浮显示 tooltip */
+.project-edit-container .left-side:not(.is-expanded) .menu-item:hover .menu-tooltip {
+  opacity: 1;
+}
+
+/* 展开时隐藏 tooltip */
+.project-edit-container .left-side.is-expanded .menu-tooltip {
+  display: none;
+}
+
+/* ===== 新增:模式切换按钮 ===== */
+.project-edit-container .menu-mode-toggle {
+  height: 50px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  padding: 15px;
+  cursor: pointer;
+  border-top: 1px solid #d8dae3;
+  color: #666;
+  gap: 10px;
+  flex-shrink: 0;
+}
+
+.project-edit-container .menu-mode-toggle:hover {
+  background: #e0e4ea;
+  color: #333;
+}
+
+/* 展开时左对齐 */
+.project-edit-container .left-side.is-expanded .menu-mode-toggle {
+  justify-content: flex-start;
+  padding: 15px 20px;
+}
+
+/* ===== 新增:子菜单样式调整 ===== */
+.project-edit-container .group-detail {
+  background: rgba(0, 0, 0, 0.03);
+}
+
+.project-edit-container .group-detail .menu-item {
+  padding-left: 25px;
+}
+
+.project-edit-container .left-side.is-expanded .group-detail .menu-item {
+  padding-left: 50px;
+}
+
+/* 收起时隐藏子菜单 */
+.project-edit-container .left-side:not(.is-expanded) .group-detail {
+  display: none;
+}
+```
+
+### CSS 修改汇总表
+
+| 行号 | 原值 | 新值 | 说明 |
+|-----|------|------|-----|
+| 4799 | `width: 180px !important` | `width: 60px` | 默认收起宽度 |
+| 4808-4811 | `.menu-header {...}` | 删除或注释 | 去掉头部图片 |
+| 4814 | `height: calc(100% - 60px)` | `flex: 1` | 菜单内容自适应 |
+| 4826 | `padding: 20px 12px 20px 30px` | `padding: 15px` | 菜单项内边距 |
+| 4836 | `left: 180px` | `margin-left: auto` | 箭头位置 |
+| 4965 | `width: calc(100% - 180px)` | `flex: 1` | 右侧内容区自适应 |
+
+---
+
+## 数据结构要求
+
+菜单项需要增加 `icon` 字段:
+
+```js
+menuList: [
+  {
+    name: 'basic',
+    title: '基本信息',
+    icon: 'info',      // 新增:图标名称
+    url: '/page/xxx.jsp'
+  },
+  {
+    title: '项目设置',
+    icon: 'setting',   // 新增
+    children: [
+      { name: 'config1', title: '配置1', icon: 'config', url: '...' },
+      { name: 'config2', title: '配置2', icon: 'config', url: '...' }
+    ]
+  }
+]
+```
+
+---
+
+## 改造要点总结
+
+| 项目 | 原实现 | 新实现 |
+|-----|-------|-------|
+| 头部图片 | 有 headerImage | 删除 |
+| 菜单宽度 | 固定宽度 | 60px / 200px 切换 |
+| 文字显示 | 始终显示 | 收起时隐藏,悬浮/展开时显示 |
+| 模式切换 | 无 | collapse(悬浮展开) / fixed(始终收起) |
+| iframe 加载 | v-show 全部加载 | v-if 懒加载(点击才加载) |
+| 图标 | 无 | 每个菜单项需要 icon 字段 |
+
+---
+
+## 兼容性注意
+
+1. 需要确保 `menuList` 数据有 `icon` 字段,否则使用默认图标
+2. 懒加载后,切换回已加载的菜单不会重新加载(保持 iframe 状态)
+3. 底部按钮功能保持不变

+ 0 - 630
home.jsp

@@ -1,630 +0,0 @@
-<%@ page import="ss.WebC" %>
-<%@ page import="ss.serv.ServC" %>
-<%@ page language="java" pageEncoding="UTF-8" isELIgnored="false" %>
-<%@ taglib uri="/ssTag" prefix="ss"%>
-<!DOCTYPE html>
-<html lang="en">
-  <head>
-    <meta charset="UTF-8" />
-    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
-	<script>window.loginStatus="${empty sessionScope['ssUser']?'0':'1'}"</script>
-	<ss:skin file='main.css'/>
-	<script type="text/javascript" src="/ss/jquery/jquery.js"></script>
-	<script type="text/javascript" src="/ss/artdialog/artDialogUtil.js"></script>
-	<script type="text/javascript" src="/ss/js/base.js"></script>
-	<script> if(!window.wd) var wd={}; if(!wd.display) wd.display={}; wd.display.wdDialogId="1"; if(!wd.app) wd.app={};  wd.app.name='pms';</script>
-	<script type="text/javascript" src="/ss/js/masklayer.js"></script>
-	<script type="text/javascript" src="/ss/js/wdDialogInit.js"></script>
-	<script type="text/javascript" src="/ss/js/common.js"></script>
-	<script type="text/javascript" src="/ss/js/display.js"></script>
-	<script type="text/javascript" src="/ss/js/edit.js"></script>
-	<script type="text/javascript" src="/ss/nicescroll/jquery.nicescroll.js"></script>
-	<script type="text/javascript" src="/ss/nicescroll/jquery.nicescroll.iframehelper.min.js"></script>
-	<link rel="stylesheet" type="text/css" href="/ss/window/theme/dhtmlxwindows.css">
-	<link rel="stylesheet" type="text/css" href="/ss/window/theme/dhx_blue/dhtmlxwindows_dhx_blue.css">
-	<script type="text/javascript" src="/ss/window/dhtmlxcommon.js"></script>
-	<script type="text/javascript" src="/ss/window/dhtmlxwindows.js"></script>
-	<script type="text/javascript" src="/ss/window/dhtmlxcontainer.js"></script>
-
-		<%
-		if(pageContext.getSession().getAttribute("ssUser")==null){
-	/* 再改,去掉 loginExp.ss.jsp(写死错误信息),改用 relogin.ss.jsp。Lin
-			request.getRequestDispatcher(WebC.PPATH_loginExp).forward(request,response);
-	*/
-			request.setAttribute(ServC.REQ_msg, WebC.LOGIN_expMsg);
-			request.getRequestDispatcher(WebC.PPATH_relogin).forward(request,response);
-
-			return;
-		}
-	%>
-
-	<title>${sessionScope.projectUrlDesc}</title>
-
-	<link rel="stylesheet" type="text/css" href="/ss/window/theme/dhtmlxwindows.css">
-	<script type="text/javascript" src="/ss/window/dhtmlxcommon.js"></script>
-<%-- 去掉,上面已经有了。Lin(新UI)
-	<script type="text/javascript" src="/ss/window/dhtmlxwindows.js"></script>
---%>
-	<script type="text/javascript" src="/ss/window/dhtmlxcontainer.js"></script>
-	<script type="text/javascript" src="/ss/js/wdDialogInit.js"></script>
-	<ss:skin file='dlg.css'/>
-	<script type="text/javascript" src="/js/load.js"></script> <%-- ="/newUI/ss/js/base.js"。Lin(新UI) --%>
-
-  </head>
-
-  <body>
-
-  <!-- menu标签输出start -->
-<%--   <ss:menu/>--%>
-  <!-- menu标签输出end -->
-
-    <div id="app" >
-		<div class="self-block layout-container" :sys-mode="sysMode" v-show="isLockScreen==false">
-        <div class="header">
-			<global-header :menu-data="menuData[8]" :icon-items="iconItems"></global-header>
-        </div>
-        <div class="content-area">
-		  <global-menu :menu-items="menuData[1]"></global-menu>
-          
-          <div class="main-content">
-            <iframe
-              :src="currentPage"
-              frameborder="0"
-              
-			  ifrType="appWin"
-			  name="win2"
-			  class="appIframe"
-			  oriSrc="/initDesktop?"
-            ></iframe>
-          </div>
-        </div>
-      	</div>
-		<div class="login-container lockscreen-container" style="background-image: url(/skin/easy/images/login-bg.png)" <%-- (/newUI/skin/easy/images/login-bg.png)。Lin(新UI) --%>
-				 v-show="isLockScreen == true" @click.self="toggleRight">
-			<div class="left" @click.self="toggleRight"></div>
-			<div  class="right" :class="{ 'right--visible': isRightVisible }"
-		@click="resetTimer"
-		@mousemove="resetTimer">
-			<div class="content-area">
-				<div class="login-box">
-					<ss-login-icon class="login-icon-change-user" onclick="wd.display.exit({homepage:1})"></ss-login-icon>
-					<div class="box-header">
-						<img :src="defaultPersonalPhoto" style="margin-bottom: 15px;" />
-						<p>您好,${sessionScope['ssUser'].xm} 欢迎回来</p>
-					</div>
-					<div>
-						
-					</div>
-					<div class="box-container">
-						<form class="box-form">
-							
-							<div class="form-item">
-								<div class="icon">
-									<ss-login-icon class="login-icon-password"  />
-								</div>
-								<ss-login-input type="password" v-model="formData.password"
-									placeholder="请输入您的密码" />
-							</div>
-
-							
-							<div class="form-bar">
-								<span><ss-login-button class="login-icon-yaoyiyao" text="摇一摇登录" type="button"
-										@click="handleClick" /></span>
-								<span><ss-login-button class="login-icon-loginin" text="登录" type="button"
-										@click="unlockSessionByPassword" /></span>
-							</div>
-						</form>
-						<!-- 错误提示 -->
-						<div v-if="errInfo.status" class="err-tip">
-							<div class="time">
-								<div v-for="i in errInfo.allTime" :key="i"
-									:class="{ fill: errInfo.allTime - i < errInfo.time }"></div>
-							</div>
-							<div class="tip">{{ errInfo.tip }}</div>
-						</div>
-					</div>
-					<div class="box-footer">
-						<div class="left"></div>
-						
-					</div>
-				</div>
-			</div>
-			<div class="footer">
-				<div>服务单位:广州非繁科技有限公司</div>
-			</div>
-			
-		</div>
-	</div>
-     
-    </div>
-	<script type="text/javascript" src="/js/lockScreen.js"></script> <%-- ="/newUI/ss/js/lockScreen.js"。Lin(新UI) --%>
-<%-- 去掉。Lin(新UI)
-		 用新UI的 lockScreen.js(注意大小写)
-		 先不去掉
---%>
-	<script type="text/javascript" src="/ss/js/lockscreen.js"></script>
-
-	<ss:skin file='lock.css'/>
-			<script>
-				var body = $(window.top.document.body);
-				// $(top.document.head).append('');
-				var funcStr = " if($('#mm').attr('type') == 'password') {$('#mm').attr('type','text')} else {$('#mm').attr('type','password')}";
-				var defaultPersonalPhoto=wd.common.loadSkinFile('image/default-personalPhoto.png');
-
-				<ss:equal val='${empty sessionScope["ssUser"]["yszwj"]}' val2='false'>
-<%-- 改。Lin
-					defaultPersonalPhoto="/service?wdService=getData&path=${sessionScope['env.ry']['yszwj']}"; --%>
-					<%--defaultPersonalPhoto="/service?wdService=dlByHttp&path=${sessionScope['wd.yyh']['yszwj']}";--%>
-				defaultPersonalPhoto="/service?ssServ=dlByHttp&type=img&path=${sessionScope['ssOrigUser']['yszwj']}";
-				</ss:equal>
-
-				body.append('<div class="lock-controll-screen" style="display:none;">'+
-						'<div id="lock-screen" class="lock-screen login-js-lock-screen" style="background-color: rgb(0, 0, 0);">'+
-						'<div class="lock-controll-panel login-translucentDiv" style="position:relative;">'+
-						'<div class="login-sca" ></div>'+
-						'<div class="login-black icon-replace" title="切换登录" style="width: 22px;height: 22px;margin-right: 5px;margin-top: 5px;cursor:pointer;position:absolute;top:0;right:0;" onclick="wd.display.exit({homepage:1})"></div>'+
-						'<div class="welcomeWords" style="padding: 4px 24px;border-radius: 20px;text-align: center;"><div class="personalPhoto" style="margin-left: 98px;margin-bottom: 15px;"><img src="'+defaultPersonalPhoto+'" /></div><p class="login-unlockHello">您好,&nbsp;<input id="zh" name="zh" type="hidden" value="${sessionScope['ssUser'].xm}"></input>${sessionScope['ssUser'].xm}&nbsp;欢迎回来</p><p>&nbsp;</p></div>'+
-						'<p class="lock-controll-input clearfix" ><input  id="mm" name="mm" style="background:none !important;" class="login-header_password_sp login-input login-unlockInput" type="password" /><span class="ksmm icon-eye" onclick="'+funcStr+'"></span><button style="background-size:unset;" id="unlockByPassword" class="lock-controll-button icon-enter content-invertButton"></button><button id="unlockByApp" class="lock-controll-button content-invertButton invertIcon-mobile"></button><span class="icon-countdownButton" style="position: absolute;top: 0px;width: 45px;border-radius: 3px;right: -94px;line-height: 30px;text-align: center;"></span></p>'+
-						'<p class="lock-controll-hint"><span style="text-align: center;display: block;font-size: 14px;margin-top: 10px;color: #f00;" id="lock-msg"></span></p>'+
-						'<p class="lock-controll-button-container" style="display: flex;align-items: center;justify-content: space-between;"><button id="unlockByVoice" style="display:none" class="lock-controll-button login-jslock-button login-unlockByVoice">按住说话</button></p>'+
-						'</div>'+
-						'</div>'+
-						'<div class="home-clock desktop-time">12:12</div>'+
-						'</div>');
-				
-				body.append('<div id="background-desktop" class="background-desktop" style="display:none;"></div>');
-				body.append('<ul class="home-tool desktop-time clearfix" style="display:none">' +
-						'<li id="pl-list"><div class="pl-list-container"><div class="pl-list"></div><div id="pl-page" class="pl-page"></div></div><a href="#" class="icon-forum listIcon"></a></li>' +
-						'<li id="dz-count"><div class="dz-count" id="dz-count"><div id="dz-count-text" class="login-dz-count-text"></div></div><a href="#" class="icon-like listIcon"></a></li>' +
-						'<li id="pic-info"><div class="pic-info login-pic-info"><table><tr><th>作者</th><td id="pic-zz-text"></td></tr><tr><th>发布时间</th><td id="pic-fbsj-text"></td></tr><tr><th>名称</th><td id="pic-mc-text"></td></tr></table></div><a href="#" class="icon-info listIcon"></a></li>' +
-						'</ul>');
-
-				/** 锁屏监听处理开始 **/
-				var lockScreenData = {
-					url1: '<ss:serv name='wd.lockSession' parm='{"wdConfirmationCaptchaService":"0"}'/>',
-					url2: '<ss:serv name='wd.checkIsUnlockedByApp' parm='{"wdConfirmationCaptchaService":"0"}'/>',
-					url3: '<ss:serv name='unlockByPwd' parm='{"wdConfirmationCaptchaService":"0"}'/>',
-					url4: '<ss:serv name='loadDeskImg' parm='{"wdConfirmationCaptchaService":"0"}'/>',
-					url5: '<ss:serv name='pl_cxajax' parm='{"wdConfirmationCaptchaService":"0"}'/>',
-					url6: 'wd.display.showComponent({show:["wdDialog"],url:"<ss:serv name='pl_cx' parm='{"wdConfirmationCaptchaService":"0"}' dest='pl_cx'/>",title:"pl_cx",width:650,height:555});',
-					url7: '<ss:serv name='nr_dz' parm='{"wdConfirmationCaptchaService":"0"}'/>',
-					url8: '<ss:serv name='wrLockStat' parm='{"wdConfirmationCaptchaService":"0"}'/>'
-				};
-				// 将锁屏需要的东西放进sessionStorage里
-				sessionStorage.setItem("lockScreenData",JSON.stringify(lockScreenData));
-				// 获取sessionStorage里用户设置的锁屏时间
-				var time = sessionStorage.getItem("lockTime");
-				//var time = 2;
-				console.log("用户设置的锁屏时间",time)
-				if(!time){
-					time = 15;
-				}
-				// 实例化锁屏方法,time分钟后锁屏
-				// var lock = new LockScreen($(top.document).find('.lock-controll-screen'),$(top.document).find('#home-background'),$(top.document).find('.home-tool'),time,lockScreenData);
-				
-				// 键盘按下重新设置锁屏
-				// $(document).keydown(function(event){
-				// 	// time分钟后重新锁屏
-				// 	lock.setupAutoLock(time);
-				// });
-				// 鼠标移动重新设置锁屏
-				// document.onmousemove = function() {
-				// 	// time分钟后重新锁屏
-				// 	lock.setupAutoLock(time);
-				// }
-				/** 锁屏监听处理结束 **/
-
-				function lockScreenFun(){
-					console.log("锁屏点击了2");
-					wd.display.beaconLogin("loginOut");
-					$(top.document).find('#background-desktop').css('display','block');
-					$.ajax({
-						type: 'POST',
-						url: '<ss:serv name='wrLockStat' parm='{"wdConfirmationCaptchaService":"0"}'/>',
-						data: {},
-						async: false,
-						success: function (data) {
-							console.log("成功锁屏");
-							lock.lockSession(time);
-						},
-					});
-				}
-				wd.topWindow.lockScreen=function(){
-					$('#lock').trigger("click");
-				}
-
-				var passwordeye = $('.login-eyeIcon');
-				var showPwd = $(".login-unlockInput");
-				passwordeye.on('click', function() {
-					console.log(1111111111111);
-					if(showPwd.prop('type') == 'text') {
-						showPwd.prop('type', 'password');
-					} else {
-						showPwd.prop('type', 'text');
-					};
-				});
-
-				var kscs =parseInt('<%=base.SsC.LOGIN_maxNum %>');
-				var cwcs = 0;
-				var cs="";
-				for(let i = 1;i<=kscs;i++){
-					if(i>cwcs){
-						cs += '<span class="login-sc login-used login-unused" style="display:none;width: 8px;height: 8px;border-radius: 50%;float: left;margin-right: 5px;" time="'+i+'"></span>';
-					}else{
-						cs += '<span class="login-sc login-used login-used" style="display:none;width: 8px;height: 8px;border-radius: 50%;float: left;margin-right: 5px;" time="'+i+'"></span>';
-					}
-				}
-
-				$(".login-sca").append(cs);
-
-				console.log("出去了");
-
-				
-
-				function goToIndex() {
-						delCookie("userId");
-						var sbbs = $("input[name='sbbs']").val();
-						var ysbbs = $("input[name='ysbbs']").val();
-						window.location.href = "/index?homepage=1&sbbs=" + sbbs+"&ysbbs=" + ysbbs;
-				}
-				function getCookie(name){
-					var arr,reg=new RegExp("(^| )"+name+"=([^;]*)(;|$)");
-					if(arr=document.cookie.match(reg))
-						return unescape(arr[2]);
-					else
-						return null;
-				}
-				function delCookie(name){
-					var exp = new Date();
-					exp.setTime(exp.getTime() - 1);
-					var cval=getCookie(name);
-					if(cval!=null)
-						document.cookie= name + "="+cval+";expires="+exp.toGMTString();
-				}
-			</script>
-			
-    <script type="module">
-	
-      import { eventBus, EVEN_VAR } from "/js/vue/EventBus.js"; <%-- "/newUI/ss/js/EventBus.js"。Lin(新UI) --%>
-      SS.ready(function() {
-        if (!window.sharedEventBus) {
-          window.sharedEventBus = eventBus;
-        }
-        
-        const sysMode = {
-          read: {
-            key: "read",
-            icon: "setting",
-          },
-          edit: {
-            key: "edit",
-            icon: "check",
-          },
-        };
-		const currentMode = Vue.ref(sysMode.read.key);
-        const toggoleSysMode = function (key) {
-            let newKey = sysMode.edit.key;
-            if (currentMode.value === sysMode.edit.key) {
-                newKey = sysMode.read.key;
-				// SYBJCTRL.saveedit(SESSION_STATE); //保存编辑模式
-            }else{
-				wd.topWindow.gxhymWindow.userEdit('gr');
-				// wd.topWindow.gxhymWindow.userEdit("gf"); //打开编辑模式
-			}
-            // 设置系统模式
-            currentMode.value = newKey;
-            eventBus.publish(EVEN_VAR.systemEditModelChange, newKey);
-        }
-        // 调用组件中的初始化方法
-        window.SS.dom.initializeFormApp({
-          el: "#app",
-          data() {
-            return {
-				lockTime: sessionStorage.getItem("lockTime") || 15,
-				isLockScreen: ${!empty sessionScope.isLockScreen},
-				isRightVisible: false,
-				hideTimer: null,
-				defaultPersonalPhoto: "",
-				errInfo: {
-					status: false,
-					time: 5,
-					allTime: 5,
-					tip: "",
-				},
-				formData: {
-					password: "",
-
-				},
-              sysMode: sysMode.read.key,
-              currentPage: "/initDesktop?",
-              menuData: {
-				"8": //系统菜单(左上角LOGO下拉出来的菜单)
-				[],
-				"1"://侧方菜单(主菜单)
-				[{
-					desc: "首页",
-					icon: "nav-icon-home",
-					pid:"00001",
-					type:"2",
-					url:'/initDesktop?'
-				}]
-              },
-			  iconItems: [
-			 	{ name: 'question', size: '22px', class: 'header-help', action: () => wd.display.showComponent({show:["wdDialog"],url:"<ss:serv name='querySYSHelp' parm='{"wdConfirmationCaptchaService":"0","ishelp":"true","dialogid":"1"}' dest='cmsPlay'/>",title:"使用指南",width:900,height:800,minHeight:1,maxHeight:800}) },
-				{ name: 'check', size: '22px',class: 'header-save', condition: () => currentMode.value === sysMode.edit.key, action: () => toggoleSysMode()},
-				{ name: 'setting-fill', size: '22px', class: 'header-setting',condition: () => currentMode.value !== sysMode.edit.key, action: () => toggoleSysMode() },
-				{ name: 'list-fill', size: '22px', class: 'header-menu', action: () => console.log('list-fill clicked') },
-				{ name: 'topic-fill', size: '22px', class: 'header-skin', action: () => wd.display.showComponent({show:["wdDialog"],url:"<ss:serv name='gxhpf_cx' parm='{"wdConfirmationCaptchaService":"0"}' dest='ty_hf'/>",title:"换肤",width:799,height:757}) },
-				{ name: 'lock-fill', size: '22px', class: 'header-lock', action: () => this.lockScreenFun() },
-				{ name: 'quit', class: 'big', size: '36px', class: 'header-logout', action: () => wd.display.exit() },
-			  ],
-            };
-          },
-          methods: {
-			setupAutoLock() {
-              if(this.autoLockTimer) {
-                clearTimeout(this.autoLockTimer);
-              }
-              this.autoLockTimer = setTimeout(() => {
-				console.log('自动锁屏');
-                this.lockScreenFun();
-              }, this.lockTime * 60 * 1000);
-            },
-            // 编辑模式变化
-            sysEditModelChange(mode) {
-              this.sysMode = mode;
-            },
-            currentPageChange(page) {
-              this.currentPage = "./" + page;
-            }, 
-			showErrorMsg(msg,sydlcs,zcs){
-				console.log(msg,sydlcs,zcs);
-				var kscs = zcs;
-				var cs = '';
-				// for (let i = 1; i <= kscs; i++) {
-				// 	if (i <= (zcs - sydlcs)) {
-				// 		cs = '<span class="login-sc login-used login-used" style="width: 8px;height: 8px;display:block;border-radius: 50%;float: left;margin-right: 5px;" time="' + i + '"></span>';
-				// 	} else {
-				// 		cs = '<span class="login-sc login-used login-unused" style="width: 8px;height: 8px;display: block;border-radius: 50%;float: left;margin-right: 5px;" time="' + i + '"></span>';
-				// 	}
-				// 	console.log(cs);
-					
-				// }
-				this.errInfo.time = sydlcs;
-				this.errInfo.allTime = zcs;
-				this.errInfo.tip = msg;
-				this.errInfo.status = true;
-
-				if (sydlcs == zcs) {
-					this.errInfo.status = false;
-				}
-
-				if (0 >= sydlcs) {
-					this.errInfo.status = true;
-					this.errInfo.time = 0;
-					this.errInfo.allTime = 5;
-					this.errInfo.tip = msg;
-					return false;
-				} else {
-					this.errInfo.status = true;
-					this.errInfo.tip = msg;
-				}
-			},
-			lockScreenFun(){
-				console.log("锁屏点击了1");
-				this.isLockScreen = true;
-				$("#app").css("position", "relative");
-				wd.display.beaconLogin("loginOut");
-				$.ajax({
-					type: 'POST',
-					url: '<ss:serv name='wrLockStat' parm='{"wdConfirmationCaptchaService":"0"}'/>',
-					data: {},
-					async: false,
-					success: function (data) {
-						console.log("成功锁屏");
-						// lock.lockSession(time);
-					},
-				});
-			},
-			unlockSessionByPassword(){
-				console.log("解锁");
-				$("#app").css("position", "");
-				var mm=this.formData.password;
-				if(!mm){
-					this.errInfo.status = true;
-					this.errInfo.tip = "请输入密码";
-					this.errInfo.time = 5;
-					return;
-				}
-				var that = this;
-				$.ajax({
-					url: '<ss:serv name='unlockByPwd' parm='{"wdConfirmationCaptchaService":"0"}'/>',
-					dataType: 'json',
-					type: 'POST',
-					data: {
-						mm: mm,
-					},
-					success: function(data) {
-						// context.target.find('#lock-msg').html(data.msg);
-						if (data.code == -1) {
-							that.showErrorMsg(data.msg, data.sydlcs, data.zcs);
-						}
-						if (data.code == 0) {
-							that.isLockScreen = false;
-							that.formData.password = "";
-							that.errInfo.status = false;
-							that.errInfo.time = 5;
-							that.errInfo.allTime = 5;
-						}
-					},
-				});
-			},
-			changeUser(){
-				console.log('Button clicked!', event);
-			},
-			toggleRight() {
-				this.isRightVisible = !this.isRightVisible;
-				
-				// 清除之前的定时器
-				if (this.hideTimer) {
-					clearTimeout(this.hideTimer);
-				}
-				
-				// 设置新的定时器
-				if (this.isRightVisible) {
-					this.hideTimer = setTimeout(() => {
-					this.isRightVisible = false;
-					}, 10000);
-				}
-			},
-			// 当用户在右侧区域操作时,重置定时器
-			resetTimer() {
-				if (this.hideTimer) {
-					clearTimeout(this.hideTimer);
-				}
-				this.hideTimer = setTimeout(() => {
-					this.isRightVisible = false;
-				}, 10000);
-			}
-          },
-          mounted() {
-			// console.log(window.SS)
-			console.log(window.top.SS)
-
-  			window.top.SS.lockScreenService.init(this);
-            eventBus.subscribe(EVEN_VAR.systemEditModelChange,this.sysEditModelChange);
-            eventBus.subscribe(EVEN_VAR.currentPage, this.currentPageChange);
-			// 监听锁屏
-			// 设置键盘和鼠标事件监听
-			document.addEventListener('keydown', () => {
-              this.setupAutoLock();
-            });
-            
-            document.addEventListener('mousemove', () => {
-              this.setupAutoLock();
-            });
-			this.setupAutoLock();
-
-			<ss:equal val='${empty sessionScope.isLockScreen}' val2='false'>
-				this.lockScreenFun();
-			</ss:equal>
-			this.defaultPersonalPhoto = wd.common.loadSkinFile('image/default-personalPhoto.png');
-			// 如果用户有自定义头像,则使用自定义头像
-			<ss:equal val='${empty sessionScope["ssUser"]["yszwj"]}' val2='false'>
-				<%-- 改。Lin
-				defaultPersonalPhoto="/service?wdService=getData&path=${sessionScope['env.ry']['yszwj']}"; --%>
-				<%--this.defaultPersonalPhoto="/service?wdService=dlByHttp&path=${sessionScope['wd.yyh']['yszwj']}";--%>
-			  this.defaultPersonalPhoto="/service?ssServ=dlByHttp&type=img&path=${sessionScope['ssOrigUser']['yszwj']}";
-			</ss:equal>
-
-			const that = this;
-
-			$.ajax({
-				type: 'POST',
-				
-				url: '<ss:serv name='wrMenuList'/>',
-				async: false,
-				dataType: 'json',
-				success: function (data) {
-					// alert('菜单数据:'+JSON.stringify(data));
-					that.menuData = data;
-
-
-
-					<%-- 测试新UI临时写死 start --%>
-
-					// that.menuData["1"].unshift({
-					// 	desc: "单位",
-					// 	icon: "nav-icon-home",
-					// 	pid:"00001",
-					// 	type:"2",
-					// 	url:'<ss:serv name='dw_cx' dest='objList_bk' parm='{}'/>'
-					// });
-
-					// that.menuData["1"].unshift({
-					// 	desc: "在用单位-部门",
-					// 	icon: "nav-icon-home",
-					// 	pid:"00001",
-					// 	type:"2",
-					// 	url:'<ss:serv name='bm_cx' dest='1objList' parm='{dwid:"101122",ssObjId:"101122",ssObjName:"dw",dataType:"change",ParentViewObject:"dw"}'/>'
-					// });
-
-					// that.menuData["1"].unshift({
-					// 	desc: "人员",
-					// 	icon: "nav-icon-person",
-					// 	pid:"00001",
-					// 	type:"2",
-					// 	url:'<ss:serv name='ry_cx' dest='1ryList' parm='{}'/>'
-					// });
-					<%-- 测试新UI临时写死 end --%>
-
-					that.menuData["1"].unshift({
-						desc: "首页",
-						icon: "icon-shouye",  // v3.0 改为使用新图标库 by xu 20251215
-						pid:"00001",
-						type:"2",
-						url:'/initDesktop?'
-					});
-
-					// v3.0 设置菜单图标 - 使用业务图标库 by xu 20251215
-					that.menuData["1"].forEach(item => {
-						// 一级菜单(文件夹类型)- 有同名二级菜单的用同样图标
-						if(item.id === "1021775") item.icon = "icon-obj-ry";     // 人员
-						if(item.id === "1021812") item.icon = "icon-obj-xy";     // 学员
-						if(item.id === "1021809") item.icon = "icon-biz-grxf";   // 个人消费
-						if(item.id === "1021783") item.icon = "icon-biz-men";    // 门
-						if(item.id === "1021806") item.icon = "icon-caipin";     // 菜品
-						if(item.id === "1021786") item.icon = "icon-biz-rc";     // 日程
-						if(item.id === "1021789") item.icon = "icon-biz-xc";     // 巡查
-						if(item.id === "1021793") item.icon = "icon-biz-kq";     // 考勤
-						if(item.id === "1021795") item.icon = "icon-biz-wp";     // 物品
-						if(item.id === "1021804") item.icon = "icon-biz-cl";     // 车辆
-						// 评价(1021780)、场地(1021800) 暂无图标,使用默认文件夹图标
-
-						// 二级菜单使用对象图标
-						if(item.id === "ry_search") item.icon = "icon-obj-ry";   // 人员
-						if(item.id === "gw_search") item.icon = "icon-obj-gw";   // 岗位
-						if(item.id === "qz_search") item.icon = "icon-obj-qz";   // 群组
-						if(item.id === "dw_search") item.icon = "icon-obj-dw";   // 单位
-						if(item.id === "xy_search") item.icon = "icon-obj-xy";   // 学员
-						if(item.id === "grcz_search") item.icon = "icon-obj-grcz"; // 个人充值
-						if(item.id === "xfj_search") item.icon = "icon-obj-xfj";   // 消费机
-						if(item.id === "jcjl_search") item.icon = "icon-obj-jcjl"; // 进出记录
-						if(item.id === "mjd_search") item.icon = "icon-obj-mjd";   // 门禁点
-						if(item.id === "mtcp_search") item.icon = "icon-mingricaipin"; // 明天菜品
-						if(item.id === "cp_search") item.icon = "icon-caipin";     // 菜品
-						if(item.id === "rc_search") item.icon = "icon-biz-rc";     // 日程
-						if(item.id === "rcjh_search") item.icon = "icon-obj-rcjh"; // 日程计划
-						if(item.id === "xcdjl_search") item.icon = "icon-obj-xcjl"; // 巡查记录
-						if(item.id === "xcd_search") item.icon = "icon-obj-xcd";   // 巡查点
-						if(item.id === "kqjl_search") item.icon = "icon-obj-kqjl"; // 考勤记录
-						if(item.id === "wp_search") item.icon = "icon-biz-wp";     // 物品
-						if(item.id === "cl_search") item.icon = "icon-biz-cl";     // 车辆
-						if(item.id === "cd_search") item.icon = "icon-biz-cd";     // 场地
-					});
-				},
-			});
-
-			// 初始化菜单模式为收起(设置CSS变量)
-			const layoutContainer = document.querySelector('.layout-container');
-			if (layoutContainer) {
-				layoutContainer.style.setProperty('--left-side-width', '60px');
-			}
-          },
-          unmounted() {
-			// 清理定时器和事件监听
-            if(this.autoLockTimer) {
-              clearTimeout(this.autoLockTimer);
-            }
-            document.removeEventListener('keydown', this.setupAutoLock);
-            document.removeEventListener('mousemove', this.setupAutoLock);
-            eventBus.clear(
-              EVEN_VAR.systemEditModelChange,
-              this.sysEditModelChange
-            );
-          },
-        });
-    });
-    </script>
-  </body>
-</html>

+ 108 - 48
js/vue/ss-components.js

@@ -5711,20 +5711,19 @@ import { EVEN_VAR } from "./EventBus.js";
    * @property {Object} [activeMenu] - 当前选中的菜单项,不传则自动选择第一个可选菜单
    * @property {Array} footerButtons - 底部按钮配置列表
 
+   */
+  /**
+   * SsSubTab 左侧菜单+iframe内容组件
+   * v3.0 改造:去掉顶部图片,改为图标+悬浮模式,iframe懒加载 by xu 20251216
    */
   const SsSubTab = {
     name: "SsSubTab",
     props: {
-      headerImage: {
-        type: String,
-        default: "",
-      },
       menuList: {
         type: Array,
         required: true,
       },
       activeMenu: {
-        // 只需要传入标题
         type: String,
         default: "",
       },
@@ -5736,9 +5735,59 @@ import { EVEN_VAR } from "./EventBus.js";
         type: Boolean,
         default: true,
       },
+      // v3.0 新增:菜单模式 collapse(悬浮展开) / fixed(始终收起) by xu 20251216
+      initialMode: {
+        type: String,
+        default: 'collapse',
+      },
     },
     emits: ["menu-change", "footer-click"],
     setup(props, { emit }) {
+      // v3.0 新增:默认图标映射,使用icon-biz图标 by xu 20251216
+      const defaultIcons = [
+        'icon-obj-ry',       // 人员
+        'icon-obj-dw',       // 单位
+        'icon-obj-gw',       // 岗位
+        'icon-biz-rc',       // 人才
+        'icon-biz-xc',       // 巡查
+        'icon-biz-cl',       // 材料
+        'icon-biz-men',      // 门
+        'icon-obj-xy'        // 协议
+      ];
+      const getMenuIcon = (item, index) => {
+        if (item.icon) return item.icon;
+        // 返回完整的 class:menu-icon (字体族) + 具体图标类
+        return 'menu-icon ' + defaultIcons[index % defaultIcons.length];
+      };
+
+      // v3.0 新增:菜单模式管理 by xu 20251216
+      const menuMode = ref(props.initialMode);
+      const isHovering = ref(false);
+
+      const toggleMenuMode = () => {
+        menuMode.value = menuMode.value === 'collapse' ? 'fixed' : 'collapse';
+      };
+
+      const onMouseEnter = () => {
+        if (menuMode.value === 'collapse') {
+          isHovering.value = true;
+        }
+      };
+      const onMouseLeave = () => {
+        isHovering.value = false;
+      };
+
+      const isExpanded = computed(() => {
+        return menuMode.value === 'collapse' && isHovering.value;
+      });
+
+      // v3.0 新增:iframe 懒加载,点击才加载 by xu 20251216
+      const loadedMenus = ref(new Set());
+
+      const isMenuLoaded = (menuName) => {
+        return loadedMenus.value.has(menuName);
+      };
+
       // 根据标题找到对应的菜单项
       const findMenuByTitle = (title) => {
         for (const item of props.menuList) {
@@ -5758,10 +5807,8 @@ import { EVEN_VAR } from "./EventBus.js";
           const menu = findMenuByTitle(props.activeMenu);
           if (menu) return menu;
         }
-
         const firstItem = props.menuList[0];
         if (!firstItem) return null;
-
         return firstItem.children?.length > 0
             ? firstItem.children[0]
             : firstItem;
@@ -5782,9 +5829,20 @@ import { EVEN_VAR } from "./EventBus.js";
           }
       );
 
+      // 初始化:默认选中项加入已加载集合
+      watch(currentMenu, (menu) => {
+        if (menu?.name) {
+          loadedMenus.value.add(menu.name);
+        }
+      }, { immediate: true });
+
       // 选择菜单项时触发 menu-change 钩子
       const selectItem = (item) => {
         currentMenu.value = item;
+        // 标记为已加载
+        if (item.name) {
+          loadedMenus.value.add(item.name);
+        }
         emit("menu-change", item);
       };
 
@@ -5797,18 +5855,24 @@ import { EVEN_VAR } from "./EventBus.js";
         currentMenu,
         selectItem,
         handleFooterClick,
+        menuMode,
+        isHovering,
+        isExpanded,
+        toggleMenuMode,
+        onMouseEnter,
+        onMouseLeave,
+        isMenuLoaded,
+        getMenuIcon,
       };
     },
     template: `
           <div class="project-edit-container">
-              <div class="left-side" v-if="leftDisplay">
-              
-                  <!-- 头部图片 -->
-                  <div v-if="headerImage" class="menu-header">
-                      <div class="thumb">
-                          <img :src="headerImage" style="object-fit: cover;width: 100%;height: 100%;" />
-                      </div>
-                  </div>
+              <div class="left-side"
+                   v-if="leftDisplay"
+                   :data-mode="menuMode"
+                   :class="{ 'is-expanded': isExpanded }"
+                   @mouseenter="onMouseEnter"
+                   @mouseleave="onMouseLeave">
 
                   <!-- 菜单内容 -->
                   <div class="menu-content">
@@ -5817,70 +5881,66 @@ import { EVEN_VAR } from "./EventBus.js";
                               <!-- 分组菜单 -->
                               <div v-if="menuItem.children?.length > 0" class="group">
                                   <div class="menu-item" @click="menuItem.open = !menuItem.open">
-                                      <span>{{ menuItem.title }}</span>
-                                      
+                                      <ss-icon :class="getMenuIcon(menuItem, i)" />
+                                      <span class="menu-label">{{ menuItem.title }}</span>
                                       <span class="arrow">
-                                          <ss-icon :name="menuItem.open ? 'arrow-up' : 'arrow-down'" size="20px" />
+                                          <ss-icon :class="menuItem.open ? 'menu-icon icon-jiantou-shang' : 'menu-icon icon-jiantou-xia'" />
                                       </span>
+                                      <div class="menu-tooltip">{{ menuItem.title }}</div>
                                   </div>
                                   <div v-show="menuItem.open" class="group-detail">
-                                      <div v-for="(item, j) in menuItem.children" 
-                                          :key="j" 
+                                      <div v-for="(item, j) in menuItem.children"
+                                          :key="j"
                                           class="menu-item"
                                           :class="{ active: item.name === currentMenu?.name }"
-                                          @click="selectItem(item)"
-                                      >
-                                          {{ item.title }}
-                                           
-                                           &nbsp;
+                                          @click="selectItem(item)">
+                                          <ss-icon :class="getMenuIcon(item, j)" />
+                                          <span class="menu-label">{{ item.title }}</span>
                                           <span class="menu-item-point" v-if="item.cgxList || item.objectList"></span>
                                       </div>
                                   </div>
                               </div>
                               <!-- 普通菜单项 -->
-                              <div v-else 
+                              <div v-else
                                   class="menu-item"
                                   :class="{ active: menuItem.name === currentMenu?.name }"
-                                  @click="selectItem(menuItem)"
-                              >
-                                    {{ menuItem.title }}
-                                   &nbsp;
+                                  @click="selectItem(menuItem)">
+                                  <ss-icon :class="getMenuIcon(menuItem, i)" />
+                                  <span class="menu-label">{{ menuItem.title }}</span>
                                   <span class="menu-item-point" v-if="menuItem.cgxList || menuItem.objectList"></span>
+                                  <div class="menu-tooltip">{{ menuItem.title }}</div>
                               </div>
                           </template>
                       </div>
                   </div>
-                  
+
+                  <!-- v3.0 模式切换按钮,只显示图标 by xu 20251216 -->
+                  <div class="menu-mode-toggle" @click="toggleMenuMode">
+                      <ss-icon class="menu-base-icon icon-qiehuan" />
+                  </div>
+
                   <!-- 底部按钮 -->
-                  <div v-if="footerButtons.length > 0" 
+                  <div v-if="footerButtons.length > 0"
                       class="sub-tab-menu-footer"
-                      @click="footerButtons[0].onclick"
-                  >
+                      @click="footerButtons[0].onclick">
                       <div>{{ footerButtons[0].text }}</div>
-                      <ss-icon 
-                          v-if="footerButtons.length > 1" 
-                          name="arrow-up" 
-                          size="24px" 
-                      />
-                      
-                      <!-- 悬浮按钮 -->
+                      <ss-icon v-if="footerButtons.length > 1" name="arrow-up" size="24px" />
                       <div v-if="footerButtons.length > 1" class="sub-tab-menu-popup">
-                          <div v-for="(button, index) in footerButtons.slice(1)" 
+                          <div v-for="(button, index) in footerButtons.slice(1)"
                               :key="index"
-                              @click.stop="button.onclick"
-                          >
+                              @click.stop="button.onclick">
                               {{ button.text }}
                           </div>
                       </div>
                   </div>
-                  
+
               </div>
 
-              <!-- 右侧内容区域 -->
+              <!-- 右侧内容区域 - 懒加载 iframe -->
               <div class="content-area fit-height-content" style="overflow: hidden;" :style="!leftDisplay ? { width: '100%' } : {}">
-                 
                   <template v-for="(menuItem, i) in menuList" :key="i">
-                      <iframe 
+                      <iframe
+                          v-if="isMenuLoaded(menuItem.name)"
                           :src="menuItem.url"
                           style="height: 100%;width: 100%;"
                           frameborder="0"

+ 5 - 5
js/vue/ss-index-components.js

@@ -197,8 +197,8 @@ export const GlobalMenu = {
                 name: item.desc,
                 component: item.url,
                 js: item.js,
-                // v3.0 优先使用 item.icon,没有才用默认图标 by xu 20251215
-                class: item.icon || (item.type == 1 ? 'icon-folder-close' : 'icon-shouye'),
+                // v3.0 优先使用 item.icon,没有才用 menu-base-icon + 默认图标 by xu 20251215
+                class: item.icon || (item.type == 1 ? 'menu-base-icon icon-folder-close' : 'menu-base-icon icon-shouye'),
                 itemType: item.type,
                 children: []
             }));
@@ -355,7 +355,7 @@ export const GlobalMenu = {
                     }, [
                         Vue.h('div', { class: 'menu-item-content' }, [
                             // v3.0 使用 ss-icon + 双 class (图标类 + menu-icon 组类) by xu 20251215
-                            Vue.h(SsIcon, { class: (menuItemsNew.value[0]?.class || 'icon-shouye') + ' menu-icon' }),
+                            Vue.h(SsIcon, { class: 'menu-base-icon icon-shouye'}),
                             Vue.h('div', { class: 'menu-item-label' }, menuItemsNew.value[0]?.name || '首页')
                         ])
                     ]) : null
@@ -393,7 +393,7 @@ export const GlobalMenu = {
                                 Vue.h(SsIcon, {
                                     class: (expandedMenus.value.has(icon.name)
                                         ? 'icon-folder-open'
-                                        : (icon.class || 'icon-folder-close')) + ' menu-icon'
+                                        : (icon.class || 'menu-base-icon icon-folder-close')) + ' menu-icon'
                                 }),
                                 Vue.h('div', { class: 'menu-item-label' }, icon.name || ''),
                                 // 有子菜单时显示小圆点(在一级菜单右上角)
@@ -431,7 +431,7 @@ export const GlobalMenu = {
                         class: 'menu-mode-btn',
                         onClick: toggleMenuMode
                     }, [
-                        Vue.h(SsIcon, { class: 'icon-qiehuan menu-icon' })
+                        Vue.h(SsIcon, { class: 'menu-base-icon icon-qiehuan' })
                     ])
                 ])
             ])

+ 630 - 607
page/home.jsp

@@ -1,607 +1,630 @@
-<%@ page import="ss.WebC" %>
-<%@ page import="ss.serv.ServC" %>
-<%@ page language="java" pageEncoding="UTF-8" isELIgnored="false" %>
-<%@ taglib uri="/ssTag" prefix="ss"%>
-<!DOCTYPE html>
-<html lang="en">
-  <head>
-    <meta charset="UTF-8" />
-    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
-	<script>window.loginStatus="${empty sessionScope['ssUser']?'0':'1'}"</script>
-	<ss:skin file='main.css'/>
-	<script type="text/javascript" src="/ss/jquery/jquery.js"></script>
-	<script type="text/javascript" src="/ss/artdialog/artDialogUtil.js"></script>
-	<script type="text/javascript" src="/ss/js/base.js"></script>
-	<script> if(!window.wd) var wd={}; if(!wd.display) wd.display={}; wd.display.wdDialogId="1"; if(!wd.app) wd.app={};  wd.app.name='pms';</script>
-	<script type="text/javascript" src="/ss/js/masklayer.js"></script>
-	<script type="text/javascript" src="/ss/js/wdDialogInit.js"></script>
-	<script type="text/javascript" src="/ss/js/common.js"></script>
-	<script type="text/javascript" src="/ss/js/display.js"></script>
-	<script type="text/javascript" src="/ss/js/edit.js"></script>
-	<script type="text/javascript" src="/ss/nicescroll/jquery.nicescroll.js"></script>
-	<script type="text/javascript" src="/ss/nicescroll/jquery.nicescroll.iframehelper.min.js"></script>
-	<link rel="stylesheet" type="text/css" href="/ss/window/theme/dhtmlxwindows.css">
-	<link rel="stylesheet" type="text/css" href="/ss/window/theme/dhx_blue/dhtmlxwindows_dhx_blue.css">
-	<script type="text/javascript" src="/ss/window/dhtmlxcommon.js"></script>
-	<script type="text/javascript" src="/ss/window/dhtmlxwindows.js"></script>
-	<script type="text/javascript" src="/ss/window/dhtmlxcontainer.js"></script>
-	<script type="text/javascript" src="/js/pageC.js"></script> <%-- 对象变动、修改、查看页,左则选项卡宽度 在里面定义 Ben(20251213) --%>
-
-		<%
-		if(pageContext.getSession().getAttribute("ssUser")==null){
-	/* 再改,去掉 loginExp.ss.jsp(写死错误信息),改用 relogin.ss.jsp。Lin
-			request.getRequestDispatcher(WebC.PPATH_loginExp).forward(request,response);
-	*/
-			request.setAttribute(ServC.REQ_msg, WebC.LOGIN_expMsg);
-			request.getRequestDispatcher(WebC.PPATH_relogin).forward(request,response);
-
-			return;
-		}
-	%>
-
-	<title>${sessionScope.projectUrlDesc}</title>
-
-	<link rel="stylesheet" type="text/css" href="/ss/window/theme/dhtmlxwindows.css">
-	<script type="text/javascript" src="/ss/window/dhtmlxcommon.js"></script>
-<%-- 去掉,上面已经有了。Lin(新UI)
-	<script type="text/javascript" src="/ss/window/dhtmlxwindows.js"></script>
---%>
-	<script type="text/javascript" src="/ss/window/dhtmlxcontainer.js"></script>
-	<script type="text/javascript" src="/ss/js/wdDialogInit.js"></script>
-	<ss:skin file='dlg.css'/>
-	<script type="text/javascript" src="/js/load.js"></script> <%-- ="/newUI/ss/js/base.js"。Lin(新UI) --%>
-
-  </head>
-
-  <body>
-
-  <!-- menu标签输出start -->
-<%--   <ss:menu/>--%>
-  <!-- menu标签输出end -->
-
-    <div id="app" >
-		<div class="self-block layout-container" :sys-mode="sysMode" v-show="isLockScreen==false">
-        <div class="header">
-			<global-header :menu-data="menuData[8]" :icon-items="iconItems"></global-header>
-        </div>
-        <div class="content-area">
-		  <global-menu :menu-items="menuData[1]"></global-menu>
-          
-          <div class="main-content">
-            <iframe
-              :src="currentPage"
-              frameborder="0"
-              
-			  ifrType="appWin"
-			  name="win2"
-			  class="appIframe"
-			  oriSrc="/initDesktop?"
-            ></iframe>
-          </div>
-        </div>
-      	</div>
-		<div class="login-container lockscreen-container" style="background-image: url(/skin/easy/images/login-bg.png)" <%-- (/newUI/skin/easy/images/login-bg.png)。Lin(新UI) --%>
-				 v-show="isLockScreen == true" @click.self="toggleRight">
-			<div class="left" @click.self="toggleRight"></div>
-			<div  class="right" :class="{ 'right--visible': isRightVisible }"
-		@click="resetTimer"
-		@mousemove="resetTimer">
-			<div class="content-area">
-				<div class="login-box">
-					<ss-login-icon class="login-icon-change-user" onclick="wd.display.exit({homepage:1})"></ss-login-icon>
-					<div class="box-header">
-						<img :src="defaultPersonalPhoto" style="margin-bottom: 15px;" />
-						<p>您好,${sessionScope['ssUser'].xm} 欢迎回来</p>
-					</div>
-					<div>
-						
-					</div>
-					<div class="box-container">
-						<form class="box-form">
-							
-							<div class="form-item">
-								<div class="icon">
-									<ss-login-icon class="login-icon-password"  />
-								</div>
-								<ss-login-input type="password" v-model="formData.password"
-									placeholder="请输入您的密码" />
-							</div>
-
-							
-							<div class="form-bar">
-								<span><ss-login-button class="login-icon-yaoyiyao" text="摇一摇登录" type="button"
-										@click="handleClick" /></span>
-								<span><ss-login-button class="login-icon-loginin" text="登录" type="button"
-										@click="unlockSessionByPassword" /></span>
-							</div>
-						</form>
-						<!-- 错误提示 -->
-						<div v-if="errInfo.status" class="err-tip">
-							<div class="time">
-								<div v-for="i in errInfo.allTime" :key="i"
-									:class="{ fill: errInfo.allTime - i < errInfo.time }"></div>
-							</div>
-							<div class="tip">{{ errInfo.tip }}</div>
-						</div>
-					</div>
-					<div class="box-footer">
-						<div class="left"></div>
-						
-					</div>
-				</div>
-			</div>
-			<div class="footer">
-				<div>服务单位:广州非繁科技有限公司</div>
-			</div>
-			
-		</div>
-	</div>
-     
-    </div>
-	<script type="text/javascript" src="/js/lockScreen.js"></script> <%-- ="/newUI/ss/js/lockScreen.js"。Lin(新UI) --%>
-<%-- 去掉。Lin(新UI)
-		 用新UI的 lockScreen.js(注意大小写)
-		 先不去掉
---%>
-	<script type="text/javascript" src="/ss/js/lockscreen.js"></script>
-
-	<ss:skin file='lock.css'/>
-			<script>
-				var body = $(window.top.document.body);
-				// $(top.document.head).append('');
-				var funcStr = " if($('#mm').attr('type') == 'password') {$('#mm').attr('type','text')} else {$('#mm').attr('type','password')}";
-				var defaultPersonalPhoto=wd.common.loadSkinFile('image/default-personalPhoto.png');
-
-				<ss:equal val='${empty sessionScope["ssUser"]["yszwj"]}' val2='false'>
-<%-- 改。Lin
-					defaultPersonalPhoto="/service?wdService=getData&path=${sessionScope['env.ry']['yszwj']}"; --%>
-					<%--defaultPersonalPhoto="/service?wdService=dlByHttp&path=${sessionScope['wd.yyh']['yszwj']}";--%>
-				defaultPersonalPhoto="/service?ssServ=dlByHttp&type=img&path=${sessionScope['ssOrigUser']['yszwj']}";
-				</ss:equal>
-
-				body.append('<div class="lock-controll-screen" style="display:none;">'+
-						'<div id="lock-screen" class="lock-screen login-js-lock-screen" style="background-color: rgb(0, 0, 0);">'+
-						'<div class="lock-controll-panel login-translucentDiv" style="position:relative;">'+
-						'<div class="login-sca" ></div>'+
-						'<div class="login-black icon-replace" title="切换登录" style="width: 22px;height: 22px;margin-right: 5px;margin-top: 5px;cursor:pointer;position:absolute;top:0;right:0;" onclick="wd.display.exit({homepage:1})"></div>'+
-						'<div class="welcomeWords" style="padding: 4px 24px;border-radius: 20px;text-align: center;"><div class="personalPhoto" style="margin-left: 98px;margin-bottom: 15px;"><img src="'+defaultPersonalPhoto+'" /></div><p class="login-unlockHello">您好,&nbsp;<input id="zh" name="zh" type="hidden" value="${sessionScope['ssUser'].xm}"></input>${sessionScope['ssUser'].xm}&nbsp;欢迎回来</p><p>&nbsp;</p></div>'+
-						'<p class="lock-controll-input clearfix" ><input  id="mm" name="mm" style="background:none !important;" class="login-header_password_sp login-input login-unlockInput" type="password" /><span class="ksmm icon-eye" onclick="'+funcStr+'"></span><button style="background-size:unset;" id="unlockByPassword" class="lock-controll-button icon-enter content-invertButton"></button><button id="unlockByApp" class="lock-controll-button content-invertButton invertIcon-mobile"></button><span class="icon-countdownButton" style="position: absolute;top: 0px;width: 45px;border-radius: 3px;right: -94px;line-height: 30px;text-align: center;"></span></p>'+
-						'<p class="lock-controll-hint"><span style="text-align: center;display: block;font-size: 14px;margin-top: 10px;color: #f00;" id="lock-msg"></span></p>'+
-						'<p class="lock-controll-button-container" style="display: flex;align-items: center;justify-content: space-between;"><button id="unlockByVoice" style="display:none" class="lock-controll-button login-jslock-button login-unlockByVoice">按住说话</button></p>'+
-						'</div>'+
-						'</div>'+
-						'<div class="home-clock desktop-time">12:12</div>'+
-						'</div>');
-				
-				body.append('<div id="background-desktop" class="background-desktop" style="display:none;"></div>');
-				body.append('<ul class="home-tool desktop-time clearfix" style="display:none">' +
-						'<li id="pl-list"><div class="pl-list-container"><div class="pl-list"></div><div id="pl-page" class="pl-page"></div></div><a href="#" class="icon-forum listIcon"></a></li>' +
-						'<li id="dz-count"><div class="dz-count" id="dz-count"><div id="dz-count-text" class="login-dz-count-text"></div></div><a href="#" class="icon-like listIcon"></a></li>' +
-						'<li id="pic-info"><div class="pic-info login-pic-info"><table><tr><th>作者</th><td id="pic-zz-text"></td></tr><tr><th>发布时间</th><td id="pic-fbsj-text"></td></tr><tr><th>名称</th><td id="pic-mc-text"></td></tr></table></div><a href="#" class="icon-info listIcon"></a></li>' +
-						'</ul>');
-
-				/** 锁屏监听处理开始 **/
-				var lockScreenData = {
-					url1: '<ss:serv name='wd.lockSession' parm='{"wdConfirmationCaptchaService":"0"}'/>',
-					url2: '<ss:serv name='wd.checkIsUnlockedByApp' parm='{"wdConfirmationCaptchaService":"0"}'/>',
-					url3: '<ss:serv name='unlockByPwd' parm='{"wdConfirmationCaptchaService":"0"}'/>',
-					url4: '<ss:serv name='loadDeskImg' parm='{"wdConfirmationCaptchaService":"0"}'/>',
-					url5: '<ss:serv name='pl_cxajax' parm='{"wdConfirmationCaptchaService":"0"}'/>',
-					url6: 'wd.display.showComponent({show:["wdDialog"],url:"<ss:serv name='pl_cx' parm='{"wdConfirmationCaptchaService":"0"}' dest='pl_cx'/>",title:"pl_cx",width:650,height:555});',
-					url7: '<ss:serv name='nr_dz' parm='{"wdConfirmationCaptchaService":"0"}'/>',
-					url8: '<ss:serv name='wrLockStat' parm='{"wdConfirmationCaptchaService":"0"}'/>'
-				};
-				// 将锁屏需要的东西放进sessionStorage里
-				sessionStorage.setItem("lockScreenData",JSON.stringify(lockScreenData));
-				// 获取sessionStorage里用户设置的锁屏时间
-				var time = sessionStorage.getItem("lockTime");
-				//var time = 2;
-				console.log("用户设置的锁屏时间",time)
-				if(!time){
-					time = 15;
-				}
-				// 实例化锁屏方法,time分钟后锁屏
-				// var lock = new LockScreen($(top.document).find('.lock-controll-screen'),$(top.document).find('#home-background'),$(top.document).find('.home-tool'),time,lockScreenData);
-				
-				// 键盘按下重新设置锁屏
-				// $(document).keydown(function(event){
-				// 	// time分钟后重新锁屏
-				// 	lock.setupAutoLock(time);
-				// });
-				// 鼠标移动重新设置锁屏
-				// document.onmousemove = function() {
-				// 	// time分钟后重新锁屏
-				// 	lock.setupAutoLock(time);
-				// }
-				/** 锁屏监听处理结束 **/
-
-				function lockScreenFun(){
-					console.log("锁屏点击了2");
-					wd.display.beaconLogin("loginOut");
-					$(top.document).find('#background-desktop').css('display','block');
-					$.ajax({
-						type: 'POST',
-						url: '<ss:serv name='wrLockStat' parm='{"wdConfirmationCaptchaService":"0"}'/>',
-						data: {},
-						async: false,
-						success: function (data) {
-							console.log("成功锁屏");
-							lock.lockSession(time);
-						},
-					});
-				}
-				wd.topWindow.lockScreen=function(){
-					$('#lock').trigger("click");
-				}
-
-				var passwordeye = $('.login-eyeIcon');
-				var showPwd = $(".login-unlockInput");
-				passwordeye.on('click', function() {
-					console.log(1111111111111);
-					if(showPwd.prop('type') == 'text') {
-						showPwd.prop('type', 'password');
-					} else {
-						showPwd.prop('type', 'text');
-					};
-				});
-
-				var kscs =parseInt('<%=base.SsC.LOGIN_maxNum %>');
-				var cwcs = 0;
-				var cs="";
-				for(let i = 1;i<=kscs;i++){
-					if(i>cwcs){
-						cs += '<span class="login-sc login-used login-unused" style="display:none;width: 8px;height: 8px;border-radius: 50%;float: left;margin-right: 5px;" time="'+i+'"></span>';
-					}else{
-						cs += '<span class="login-sc login-used login-used" style="display:none;width: 8px;height: 8px;border-radius: 50%;float: left;margin-right: 5px;" time="'+i+'"></span>';
-					}
-				}
-
-				$(".login-sca").append(cs);
-
-				console.log("出去了");
-
-				
-
-				function goToIndex() {
-						delCookie("userId");
-						var sbbs = $("input[name='sbbs']").val();
-						var ysbbs = $("input[name='ysbbs']").val();
-						window.location.href = "/index?homepage=1&sbbs=" + sbbs+"&ysbbs=" + ysbbs;
-				}
-				function getCookie(name){
-					var arr,reg=new RegExp("(^| )"+name+"=([^;]*)(;|$)");
-					if(arr=document.cookie.match(reg))
-						return unescape(arr[2]);
-					else
-						return null;
-				}
-				function delCookie(name){
-					var exp = new Date();
-					exp.setTime(exp.getTime() - 1);
-					var cval=getCookie(name);
-					if(cval!=null)
-						document.cookie= name + "="+cval+";expires="+exp.toGMTString();
-				}
-			</script>
-			
-    <script type="module">
-	
-      import { eventBus, EVEN_VAR } from "/js/vue/EventBus.js"; <%-- "/newUI/ss/js/EventBus.js"。Lin(新UI) --%>
-      SS.ready(function() {
-        if (!window.sharedEventBus) {
-          window.sharedEventBus = eventBus;
-        }
-        
-        const sysMode = {
-          read: {
-            key: "read",
-            icon: "setting",
-          },
-          edit: {
-            key: "edit",
-            icon: "check",
-          },
-        };
-		const currentMode = Vue.ref(sysMode.read.key);
-        const toggoleSysMode = function (key) {
-            let newKey = sysMode.edit.key;
-            if (currentMode.value === sysMode.edit.key) {
-                newKey = sysMode.read.key;
-				// SYBJCTRL.saveedit(SESSION_STATE); //保存编辑模式
-            }else{
-				wd.topWindow.gxhymWindow.userEdit('gr');
-				// wd.topWindow.gxhymWindow.userEdit("gf"); //打开编辑模式
-			}
-            // 设置系统模式
-            currentMode.value = newKey;
-            eventBus.publish(EVEN_VAR.systemEditModelChange, newKey);
-        }
-        // 调用组件中的初始化方法
-        window.SS.dom.initializeFormApp({
-          el: "#app",
-          data() {
-            return {
-				lockTime: sessionStorage.getItem("lockTime") || 15,
-				isLockScreen: ${!empty sessionScope.isLockScreen},
-				isRightVisible: false,
-				hideTimer: null,
-				defaultPersonalPhoto: "",
-				errInfo: {
-					status: false,
-					time: 5,
-					allTime: 5,
-					tip: "",
-				},
-				formData: {
-					password: "",
-
-				},
-              sysMode: sysMode.read.key,
-              currentPage: "/initDesktop?",
-              menuData: {
-				"8": //系统菜单(左上角LOGO下拉出来的菜单)
-				[],
-				"1"://侧方菜单(主菜单)
-				[{
-					desc: "首页",
-					icon: "nav-icon-home",
-					pid:"00001",
-					type:"2",
-					url:'/initDesktop?'
-				}]
-              },
-			  iconItems: [
-			 	{ name: 'question', size: '22px', class: 'header-help', action: () => wd.display.showComponent({show:["wdDialog"],url:"<ss:serv name='querySYSHelp' parm='{"wdConfirmationCaptchaService":"0","ishelp":"true","dialogid":"1"}' dest='cmsPlay'/>",title:"使用指南",width:900,height:800,minHeight:1,maxHeight:800}) },
-				{ name: 'check', size: '22px',class: 'header-save', condition: () => currentMode.value === sysMode.edit.key, action: () => toggoleSysMode()},
-				{ name: 'setting-fill', size: '22px', class: 'header-setting',condition: () => currentMode.value !== sysMode.edit.key, action: () => toggoleSysMode() },
-				{ name: 'list-fill', size: '22px', class: 'header-menu', action: () => console.log('list-fill clicked') },
-				{ name: 'topic-fill', size: '22px', class: 'header-skin', action: () => wd.display.showComponent({show:["wdDialog"],url:"<ss:serv name='gxhpf_cx' parm='{"wdConfirmationCaptchaService":"0"}' dest='ty_hf'/>",title:"换肤",width:799,height:757}) },
-				{ name: 'lock-fill', size: '22px', class: 'header-lock', action: () => this.lockScreenFun() },
-				{ name: 'quit', class: 'big', size: '36px', class: 'header-logout', action: () => wd.display.exit() },
-			  ],
-            };
-          },
-          methods: {
-			setupAutoLock() {
-              if(this.autoLockTimer) {
-                clearTimeout(this.autoLockTimer);
-              }
-              this.autoLockTimer = setTimeout(() => {
-				console.log('自动锁屏');
-                this.lockScreenFun();
-              }, this.lockTime * 60 * 1000);
-            },
-            // 编辑模式变化
-            sysEditModelChange(mode) {
-              this.sysMode = mode;
-            },
-            currentPageChange(page) {
-              this.currentPage = "./" + page;
-            }, 
-			showErrorMsg(msg,sydlcs,zcs){
-				console.log(msg,sydlcs,zcs);
-				var kscs = zcs;
-				var cs = '';
-				// for (let i = 1; i <= kscs; i++) {
-				// 	if (i <= (zcs - sydlcs)) {
-				// 		cs = '<span class="login-sc login-used login-used" style="width: 8px;height: 8px;display:block;border-radius: 50%;float: left;margin-right: 5px;" time="' + i + '"></span>';
-				// 	} else {
-				// 		cs = '<span class="login-sc login-used login-unused" style="width: 8px;height: 8px;display: block;border-radius: 50%;float: left;margin-right: 5px;" time="' + i + '"></span>';
-				// 	}
-				// 	console.log(cs);
-					
-				// }
-				this.errInfo.time = sydlcs;
-				this.errInfo.allTime = zcs;
-				this.errInfo.tip = msg;
-				this.errInfo.status = true;
-
-				if (sydlcs == zcs) {
-					this.errInfo.status = false;
-				}
-
-				if (0 >= sydlcs) {
-					this.errInfo.status = true;
-					this.errInfo.time = 0;
-					this.errInfo.allTime = 5;
-					this.errInfo.tip = msg;
-					return false;
-				} else {
-					this.errInfo.status = true;
-					this.errInfo.tip = msg;
-				}
-			},
-			lockScreenFun(){
-				console.log("锁屏点击了1");
-				this.isLockScreen = true;
-				$("#app").css("position", "relative");
-				wd.display.beaconLogin("loginOut");
-				$.ajax({
-					type: 'POST',
-					url: '<ss:serv name='wrLockStat' parm='{"wdConfirmationCaptchaService":"0"}'/>',
-					data: {},
-					async: false,
-					success: function (data) {
-						console.log("成功锁屏");
-						// lock.lockSession(time);
-					},
-				});
-			},
-			unlockSessionByPassword(){
-				console.log("解锁");
-				$("#app").css("position", "");
-				var mm=this.formData.password;
-				if(!mm){
-					this.errInfo.status = true;
-					this.errInfo.tip = "请输入密码";
-					this.errInfo.time = 5;
-					return;
-				}
-				var that = this;
-				$.ajax({
-					url: '<ss:serv name='unlockByPwd' parm='{"wdConfirmationCaptchaService":"0"}'/>',
-					dataType: 'json',
-					type: 'POST',
-					data: {
-						mm: mm,
-					},
-					success: function(data) {
-						// context.target.find('#lock-msg').html(data.msg);
-						if (data.code == -1) {
-							that.showErrorMsg(data.msg, data.sydlcs, data.zcs);
-						}
-						if (data.code == 0) {
-							that.isLockScreen = false;
-							that.formData.password = "";
-							that.errInfo.status = false;
-							that.errInfo.time = 5;
-							that.errInfo.allTime = 5;
-						}
-					},
-				});
-			},
-			changeUser(){
-				console.log('Button clicked!', event);
-			},
-			toggleRight() {
-				this.isRightVisible = !this.isRightVisible;
-				
-				// 清除之前的定时器
-				if (this.hideTimer) {
-					clearTimeout(this.hideTimer);
-				}
-				
-				// 设置新的定时器
-				if (this.isRightVisible) {
-					this.hideTimer = setTimeout(() => {
-					this.isRightVisible = false;
-					}, 10000);
-				}
-			},
-			// 当用户在右侧区域操作时,重置定时器
-			resetTimer() {
-				if (this.hideTimer) {
-					clearTimeout(this.hideTimer);
-				}
-				this.hideTimer = setTimeout(() => {
-					this.isRightVisible = false;
-				}, 10000);
-			}
-          },
-          mounted() {
-			// console.log(window.SS)
-			console.log(window.top.SS)
-
-  			window.top.SS.lockScreenService.init(this);
-            eventBus.subscribe(EVEN_VAR.systemEditModelChange,this.sysEditModelChange);
-            eventBus.subscribe(EVEN_VAR.currentPage, this.currentPageChange);
-			// 监听锁屏
-			// 设置键盘和鼠标事件监听
-			document.addEventListener('keydown', () => {
-              this.setupAutoLock();
-            });
-            
-            document.addEventListener('mousemove', () => {
-              this.setupAutoLock();
-            });
-			this.setupAutoLock();
-
-			<ss:equal val='${empty sessionScope.isLockScreen}' val2='false'>
-				this.lockScreenFun();
-			</ss:equal>
-			this.defaultPersonalPhoto = wd.common.loadSkinFile('image/default-personalPhoto.png');
-			// 如果用户有自定义头像,则使用自定义头像
-			<ss:equal val='${empty sessionScope["ssUser"]["yszwj"]}' val2='false'>
-				<%-- 改。Lin
-				defaultPersonalPhoto="/service?wdService=getData&path=${sessionScope['env.ry']['yszwj']}"; --%>
-				<%--this.defaultPersonalPhoto="/service?wdService=dlByHttp&path=${sessionScope['wd.yyh']['yszwj']}";--%>
-			  this.defaultPersonalPhoto="/service?ssServ=dlByHttp&type=img&path=${sessionScope['ssOrigUser']['yszwj']}";
-			</ss:equal>
-
-			const that = this;
-
-			$.ajax({
-				type: 'POST',
-				
-				url: '<ss:serv name='wrMenuList'/>',
-				async: false,
-				dataType: 'json',
-				success: function (data) {
-					// alert('菜单数据:'+JSON.stringify(data));
-					that.menuData = data;
-
-
-
-					<%-- 测试新UI临时写死 start --%>
-
-					// that.menuData["1"].unshift({
-					// 	desc: "单位",
-					// 	icon: "nav-icon-home",
-					// 	pid:"00001",
-					// 	type:"2",
-					// 	url:'<ss:serv name='dw_cx' dest='objList_bk' parm='{}'/>'
-					// });
-
-					// that.menuData["1"].unshift({
-					// 	desc: "在用单位-部门",
-					// 	icon: "nav-icon-home",
-					// 	pid:"00001",
-					// 	type:"2",
-					// 	url:'<ss:serv name='bm_cx' dest='1objList' parm='{dwid:"101122",ssObjId:"101122",ssObjName:"dw",dataType:"change",ParentViewObject:"dw"}'/>'
-					// });
-
-					// that.menuData["1"].unshift({
-					// 	desc: "人员",
-					// 	icon: "nav-icon-person",
-					// 	pid:"00001",
-					// 	type:"2",
-					// 	url:'<ss:serv name='ry_cx' dest='1ryList' parm='{}'/>'
-					// });
-					<%-- 测试新UI临时写死 end --%>
-
-					that.menuData["1"].unshift({
-						desc: "首页",
-						icon: "nav-icon-home",
-						pid:"00001",
-						type:"2",
-						url:'/initDesktop?'
-					});
-
-					// 设置搜索菜单的图标
-					that.menuData["1"].forEach(item => {
-						if(item.id === "ry_search") {
-							item.icon = "nav-icon-person";
-						}
-						if(item.id === "gw_search") {
-							item.icon = "nav-icon-post"; 
-						}
-						if(item.id === "dw_search") {
-							item.icon = "nav-icon-unit";
-						}
-					});
-				},
-			});
-
-			// 初始化菜单模式为收起(设置CSS变量)
-			const layoutContainer = document.querySelector('.layout-container');
-			if (layoutContainer) {
-				layoutContainer.style.setProperty('--left-side-width', '60px');
-			}
-          },
-          unmounted() {
-			// 清理定时器和事件监听
-            if(this.autoLockTimer) {
-              clearTimeout(this.autoLockTimer);
-            }
-            document.removeEventListener('keydown', this.setupAutoLock);
-            document.removeEventListener('mousemove', this.setupAutoLock);
-            eventBus.clear(
-              EVEN_VAR.systemEditModelChange,
-              this.sysEditModelChange
-            );
-          },
-        });
-    });
-    </script>
-  </body>
-</html>
+<%@ page import="ss.WebC" %>
+<%@ page import="ss.serv.ServC" %>
+<%@ page language="java" pageEncoding="UTF-8" isELIgnored="false" %>
+<%@ taglib uri="/ssTag" prefix="ss"%>
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8" />
+    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+	<script>window.loginStatus="${empty sessionScope['ssUser']?'0':'1'}"</script>
+	<ss:skin file='main.css'/>
+	<script type="text/javascript" src="/ss/jquery/jquery.js"></script>
+	<script type="text/javascript" src="/ss/artdialog/artDialogUtil.js"></script>
+	<script type="text/javascript" src="/ss/js/base.js"></script>
+	<script> if(!window.wd) var wd={}; if(!wd.display) wd.display={}; wd.display.wdDialogId="1"; if(!wd.app) wd.app={};  wd.app.name='pms';</script>
+	<script type="text/javascript" src="/ss/js/masklayer.js"></script>
+	<script type="text/javascript" src="/ss/js/wdDialogInit.js"></script>
+	<script type="text/javascript" src="/ss/js/common.js"></script>
+	<script type="text/javascript" src="/ss/js/display.js"></script>
+	<script type="text/javascript" src="/ss/js/edit.js"></script>
+	<script type="text/javascript" src="/ss/nicescroll/jquery.nicescroll.js"></script>
+	<script type="text/javascript" src="/ss/nicescroll/jquery.nicescroll.iframehelper.min.js"></script>
+	<link rel="stylesheet" type="text/css" href="/ss/window/theme/dhtmlxwindows.css">
+	<link rel="stylesheet" type="text/css" href="/ss/window/theme/dhx_blue/dhtmlxwindows_dhx_blue.css">
+	<script type="text/javascript" src="/ss/window/dhtmlxcommon.js"></script>
+	<script type="text/javascript" src="/ss/window/dhtmlxwindows.js"></script>
+	<script type="text/javascript" src="/ss/window/dhtmlxcontainer.js"></script>
+
+		<%
+		if(pageContext.getSession().getAttribute("ssUser")==null){
+	/* 再改,去掉 loginExp.ss.jsp(写死错误信息),改用 relogin.ss.jsp。Lin
+			request.getRequestDispatcher(WebC.PPATH_loginExp).forward(request,response);
+	*/
+			request.setAttribute(ServC.REQ_msg, WebC.LOGIN_expMsg);
+			request.getRequestDispatcher(WebC.PPATH_relogin).forward(request,response);
+
+			return;
+		}
+	%>
+
+	<title>${sessionScope.projectUrlDesc}</title>
+
+	<link rel="stylesheet" type="text/css" href="/ss/window/theme/dhtmlxwindows.css">
+	<script type="text/javascript" src="/ss/window/dhtmlxcommon.js"></script>
+<%-- 去掉,上面已经有了。Lin(新UI)
+	<script type="text/javascript" src="/ss/window/dhtmlxwindows.js"></script>
+--%>
+	<script type="text/javascript" src="/ss/window/dhtmlxcontainer.js"></script>
+	<script type="text/javascript" src="/ss/js/wdDialogInit.js"></script>
+	<ss:skin file='dlg.css'/>
+	<script type="text/javascript" src="/js/load.js"></script> <%-- ="/newUI/ss/js/base.js"。Lin(新UI) --%>
+
+  </head>
+
+  <body>
+
+  <!-- menu标签输出start -->
+<%--   <ss:menu/>--%>
+  <!-- menu标签输出end -->
+
+    <div id="app" >
+		<div class="self-block layout-container" :sys-mode="sysMode" v-show="isLockScreen==false">
+        <div class="header">
+			<global-header :menu-data="menuData[8]" :icon-items="iconItems"></global-header>
+        </div>
+        <div class="content-area">
+		  <global-menu :menu-items="menuData[1]"></global-menu>
+          
+          <div class="main-content">
+            <iframe
+              :src="currentPage"
+              frameborder="0"
+              
+			  ifrType="appWin"
+			  name="win2"
+			  class="appIframe"
+			  oriSrc="/initDesktop?"
+            ></iframe>
+          </div>
+        </div>
+      	</div>
+		<div class="login-container lockscreen-container" style="background-image: url(/skin/easy/images/login-bg.png)" <%-- (/newUI/skin/easy/images/login-bg.png)。Lin(新UI) --%>
+				 v-show="isLockScreen == true" @click.self="toggleRight">
+			<div class="left" @click.self="toggleRight"></div>
+			<div  class="right" :class="{ 'right--visible': isRightVisible }"
+		@click="resetTimer"
+		@mousemove="resetTimer">
+			<div class="content-area">
+				<div class="login-box">
+					<ss-login-icon class="login-icon-change-user" onclick="wd.display.exit({homepage:1})"></ss-login-icon>
+					<div class="box-header">
+						<img :src="defaultPersonalPhoto" style="margin-bottom: 15px;" />
+						<p>您好,${sessionScope['ssUser'].xm} 欢迎回来</p>
+					</div>
+					<div>
+						
+					</div>
+					<div class="box-container">
+						<form class="box-form">
+							
+							<div class="form-item">
+								<div class="icon">
+									<ss-login-icon class="login-icon-password"  />
+								</div>
+								<ss-login-input type="password" v-model="formData.password"
+									placeholder="请输入您的密码" />
+							</div>
+
+							
+							<div class="form-bar">
+								<span><ss-login-button class="login-icon-yaoyiyao" text="摇一摇登录" type="button"
+										@click="handleClick" /></span>
+								<span><ss-login-button class="login-icon-loginin" text="登录" type="button"
+										@click="unlockSessionByPassword" /></span>
+							</div>
+						</form>
+						<!-- 错误提示 -->
+						<div v-if="errInfo.status" class="err-tip">
+							<div class="time">
+								<div v-for="i in errInfo.allTime" :key="i"
+									:class="{ fill: errInfo.allTime - i < errInfo.time }"></div>
+							</div>
+							<div class="tip">{{ errInfo.tip }}</div>
+						</div>
+					</div>
+					<div class="box-footer">
+						<div class="left"></div>
+						
+					</div>
+				</div>
+			</div>
+			<div class="footer">
+				<div>服务单位:广州非繁科技有限公司</div>
+			</div>
+			
+		</div>
+	</div>
+     
+    </div>
+	<script type="text/javascript" src="/js/lockScreen.js"></script> <%-- ="/newUI/ss/js/lockScreen.js"。Lin(新UI) --%>
+<%-- 去掉。Lin(新UI)
+		 用新UI的 lockScreen.js(注意大小写)
+		 先不去掉
+--%>
+	<script type="text/javascript" src="/ss/js/lockscreen.js"></script>
+
+	<ss:skin file='lock.css'/>
+			<script>
+				var body = $(window.top.document.body);
+				// $(top.document.head).append('');
+				var funcStr = " if($('#mm').attr('type') == 'password') {$('#mm').attr('type','text')} else {$('#mm').attr('type','password')}";
+				var defaultPersonalPhoto=wd.common.loadSkinFile('image/default-personalPhoto.png');
+
+				<ss:equal val='${empty sessionScope["ssUser"]["yszwj"]}' val2='false'>
+<%-- 改。Lin
+					defaultPersonalPhoto="/service?wdService=getData&path=${sessionScope['env.ry']['yszwj']}"; --%>
+					<%--defaultPersonalPhoto="/service?wdService=dlByHttp&path=${sessionScope['wd.yyh']['yszwj']}";--%>
+				defaultPersonalPhoto="/service?ssServ=dlByHttp&type=img&path=${sessionScope['ssOrigUser']['yszwj']}";
+				</ss:equal>
+
+				body.append('<div class="lock-controll-screen" style="display:none;">'+
+						'<div id="lock-screen" class="lock-screen login-js-lock-screen" style="background-color: rgb(0, 0, 0);">'+
+						'<div class="lock-controll-panel login-translucentDiv" style="position:relative;">'+
+						'<div class="login-sca" ></div>'+
+						'<div class="login-black icon-replace" title="切换登录" style="width: 22px;height: 22px;margin-right: 5px;margin-top: 5px;cursor:pointer;position:absolute;top:0;right:0;" onclick="wd.display.exit({homepage:1})"></div>'+
+						'<div class="welcomeWords" style="padding: 4px 24px;border-radius: 20px;text-align: center;"><div class="personalPhoto" style="margin-left: 98px;margin-bottom: 15px;"><img src="'+defaultPersonalPhoto+'" /></div><p class="login-unlockHello">您好,&nbsp;<input id="zh" name="zh" type="hidden" value="${sessionScope['ssUser'].xm}"></input>${sessionScope['ssUser'].xm}&nbsp;欢迎回来</p><p>&nbsp;</p></div>'+
+						'<p class="lock-controll-input clearfix" ><input  id="mm" name="mm" style="background:none !important;" class="login-header_password_sp login-input login-unlockInput" type="password" /><span class="ksmm icon-eye" onclick="'+funcStr+'"></span><button style="background-size:unset;" id="unlockByPassword" class="lock-controll-button icon-enter content-invertButton"></button><button id="unlockByApp" class="lock-controll-button content-invertButton invertIcon-mobile"></button><span class="icon-countdownButton" style="position: absolute;top: 0px;width: 45px;border-radius: 3px;right: -94px;line-height: 30px;text-align: center;"></span></p>'+
+						'<p class="lock-controll-hint"><span style="text-align: center;display: block;font-size: 14px;margin-top: 10px;color: #f00;" id="lock-msg"></span></p>'+
+						'<p class="lock-controll-button-container" style="display: flex;align-items: center;justify-content: space-between;"><button id="unlockByVoice" style="display:none" class="lock-controll-button login-jslock-button login-unlockByVoice">按住说话</button></p>'+
+						'</div>'+
+						'</div>'+
+						'<div class="home-clock desktop-time">12:12</div>'+
+						'</div>');
+				
+				body.append('<div id="background-desktop" class="background-desktop" style="display:none;"></div>');
+				body.append('<ul class="home-tool desktop-time clearfix" style="display:none">' +
+						'<li id="pl-list"><div class="pl-list-container"><div class="pl-list"></div><div id="pl-page" class="pl-page"></div></div><a href="#" class="icon-forum listIcon"></a></li>' +
+						'<li id="dz-count"><div class="dz-count" id="dz-count"><div id="dz-count-text" class="login-dz-count-text"></div></div><a href="#" class="icon-like listIcon"></a></li>' +
+						'<li id="pic-info"><div class="pic-info login-pic-info"><table><tr><th>作者</th><td id="pic-zz-text"></td></tr><tr><th>发布时间</th><td id="pic-fbsj-text"></td></tr><tr><th>名称</th><td id="pic-mc-text"></td></tr></table></div><a href="#" class="icon-info listIcon"></a></li>' +
+						'</ul>');
+
+				/** 锁屏监听处理开始 **/
+				var lockScreenData = {
+					url1: '<ss:serv name='wd.lockSession' parm='{"wdConfirmationCaptchaService":"0"}'/>',
+					url2: '<ss:serv name='wd.checkIsUnlockedByApp' parm='{"wdConfirmationCaptchaService":"0"}'/>',
+					url3: '<ss:serv name='unlockByPwd' parm='{"wdConfirmationCaptchaService":"0"}'/>',
+					url4: '<ss:serv name='loadDeskImg' parm='{"wdConfirmationCaptchaService":"0"}'/>',
+					url5: '<ss:serv name='pl_cxajax' parm='{"wdConfirmationCaptchaService":"0"}'/>',
+					url6: 'wd.display.showComponent({show:["wdDialog"],url:"<ss:serv name='pl_cx' parm='{"wdConfirmationCaptchaService":"0"}' dest='pl_cx'/>",title:"pl_cx",width:650,height:555});',
+					url7: '<ss:serv name='nr_dz' parm='{"wdConfirmationCaptchaService":"0"}'/>',
+					url8: '<ss:serv name='wrLockStat' parm='{"wdConfirmationCaptchaService":"0"}'/>'
+				};
+				// 将锁屏需要的东西放进sessionStorage里
+				sessionStorage.setItem("lockScreenData",JSON.stringify(lockScreenData));
+				// 获取sessionStorage里用户设置的锁屏时间
+				var time = sessionStorage.getItem("lockTime");
+				//var time = 2;
+				console.log("用户设置的锁屏时间",time)
+				if(!time){
+					time = 15;
+				}
+				// 实例化锁屏方法,time分钟后锁屏
+				// var lock = new LockScreen($(top.document).find('.lock-controll-screen'),$(top.document).find('#home-background'),$(top.document).find('.home-tool'),time,lockScreenData);
+				
+				// 键盘按下重新设置锁屏
+				// $(document).keydown(function(event){
+				// 	// time分钟后重新锁屏
+				// 	lock.setupAutoLock(time);
+				// });
+				// 鼠标移动重新设置锁屏
+				// document.onmousemove = function() {
+				// 	// time分钟后重新锁屏
+				// 	lock.setupAutoLock(time);
+				// }
+				/** 锁屏监听处理结束 **/
+
+				function lockScreenFun(){
+					console.log("锁屏点击了2");
+					wd.display.beaconLogin("loginOut");
+					$(top.document).find('#background-desktop').css('display','block');
+					$.ajax({
+						type: 'POST',
+						url: '<ss:serv name='wrLockStat' parm='{"wdConfirmationCaptchaService":"0"}'/>',
+						data: {},
+						async: false,
+						success: function (data) {
+							console.log("成功锁屏");
+							lock.lockSession(time);
+						},
+					});
+				}
+				wd.topWindow.lockScreen=function(){
+					$('#lock').trigger("click");
+				}
+
+				var passwordeye = $('.login-eyeIcon');
+				var showPwd = $(".login-unlockInput");
+				passwordeye.on('click', function() {
+					console.log(1111111111111);
+					if(showPwd.prop('type') == 'text') {
+						showPwd.prop('type', 'password');
+					} else {
+						showPwd.prop('type', 'text');
+					};
+				});
+
+				var kscs =parseInt('<%=base.SsC.LOGIN_maxNum %>');
+				var cwcs = 0;
+				var cs="";
+				for(let i = 1;i<=kscs;i++){
+					if(i>cwcs){
+						cs += '<span class="login-sc login-used login-unused" style="display:none;width: 8px;height: 8px;border-radius: 50%;float: left;margin-right: 5px;" time="'+i+'"></span>';
+					}else{
+						cs += '<span class="login-sc login-used login-used" style="display:none;width: 8px;height: 8px;border-radius: 50%;float: left;margin-right: 5px;" time="'+i+'"></span>';
+					}
+				}
+
+				$(".login-sca").append(cs);
+
+				console.log("出去了");
+
+				
+
+				function goToIndex() {
+						delCookie("userId");
+						var sbbs = $("input[name='sbbs']").val();
+						var ysbbs = $("input[name='ysbbs']").val();
+						window.location.href = "/index?homepage=1&sbbs=" + sbbs+"&ysbbs=" + ysbbs;
+				}
+				function getCookie(name){
+					var arr,reg=new RegExp("(^| )"+name+"=([^;]*)(;|$)");
+					if(arr=document.cookie.match(reg))
+						return unescape(arr[2]);
+					else
+						return null;
+				}
+				function delCookie(name){
+					var exp = new Date();
+					exp.setTime(exp.getTime() - 1);
+					var cval=getCookie(name);
+					if(cval!=null)
+						document.cookie= name + "="+cval+";expires="+exp.toGMTString();
+				}
+			</script>
+			
+    <script type="module">
+	
+      import { eventBus, EVEN_VAR } from "/js/vue/EventBus.js"; <%-- "/newUI/ss/js/EventBus.js"。Lin(新UI) --%>
+      SS.ready(function() {
+        if (!window.sharedEventBus) {
+          window.sharedEventBus = eventBus;
+        }
+        
+        const sysMode = {
+          read: {
+            key: "read",
+            icon: "setting",
+          },
+          edit: {
+            key: "edit",
+            icon: "check",
+          },
+        };
+		const currentMode = Vue.ref(sysMode.read.key);
+        const toggoleSysMode = function (key) {
+            let newKey = sysMode.edit.key;
+            if (currentMode.value === sysMode.edit.key) {
+                newKey = sysMode.read.key;
+				// SYBJCTRL.saveedit(SESSION_STATE); //保存编辑模式
+            }else{
+				wd.topWindow.gxhymWindow.userEdit('gr');
+				// wd.topWindow.gxhymWindow.userEdit("gf"); //打开编辑模式
+			}
+            // 设置系统模式
+            currentMode.value = newKey;
+            eventBus.publish(EVEN_VAR.systemEditModelChange, newKey);
+        }
+        // 调用组件中的初始化方法
+        window.SS.dom.initializeFormApp({
+          el: "#app",
+          data() {
+            return {
+				lockTime: sessionStorage.getItem("lockTime") || 15,
+				isLockScreen: ${!empty sessionScope.isLockScreen},
+				isRightVisible: false,
+				hideTimer: null,
+				defaultPersonalPhoto: "",
+				errInfo: {
+					status: false,
+					time: 5,
+					allTime: 5,
+					tip: "",
+				},
+				formData: {
+					password: "",
+
+				},
+              sysMode: sysMode.read.key,
+              currentPage: "/initDesktop?",
+              menuData: {
+				"8": //系统菜单(左上角LOGO下拉出来的菜单)
+				[],
+				"1"://侧方菜单(主菜单)
+				[{
+					desc: "首页",
+					icon: "nav-icon-home",
+					pid:"00001",
+					type:"2",
+					url:'/initDesktop?'
+				}]
+              },
+			  iconItems: [
+			 	{ name: 'question', size: '22px', class: 'header-help', action: () => wd.display.showComponent({show:["wdDialog"],url:"<ss:serv name='querySYSHelp' parm='{"wdConfirmationCaptchaService":"0","ishelp":"true","dialogid":"1"}' dest='cmsPlay'/>",title:"使用指南",width:900,height:800,minHeight:1,maxHeight:800}) },
+				{ name: 'check', size: '22px',class: 'header-save', condition: () => currentMode.value === sysMode.edit.key, action: () => toggoleSysMode()},
+				{ name: 'setting-fill', size: '22px', class: 'header-setting',condition: () => currentMode.value !== sysMode.edit.key, action: () => toggoleSysMode() },
+				{ name: 'list-fill', size: '22px', class: 'header-menu', action: () => console.log('list-fill clicked') },
+				{ name: 'topic-fill', size: '22px', class: 'header-skin', action: () => wd.display.showComponent({show:["wdDialog"],url:"<ss:serv name='gxhpf_cx' parm='{"wdConfirmationCaptchaService":"0"}' dest='ty_hf'/>",title:"换肤",width:799,height:757}) },
+				{ name: 'lock-fill', size: '22px', class: 'header-lock', action: () => this.lockScreenFun() },
+				{ name: 'quit', class: 'big', size: '36px', class: 'header-logout', action: () => wd.display.exit() },
+			  ],
+            };
+          },
+          methods: {
+			setupAutoLock() {
+              if(this.autoLockTimer) {
+                clearTimeout(this.autoLockTimer);
+              }
+              this.autoLockTimer = setTimeout(() => {
+				console.log('自动锁屏');
+                this.lockScreenFun();
+              }, this.lockTime * 60 * 1000);
+            },
+            // 编辑模式变化
+            sysEditModelChange(mode) {
+              this.sysMode = mode;
+            },
+            currentPageChange(page) {
+              this.currentPage = "./" + page;
+            }, 
+			showErrorMsg(msg,sydlcs,zcs){
+				console.log(msg,sydlcs,zcs);
+				var kscs = zcs;
+				var cs = '';
+				// for (let i = 1; i <= kscs; i++) {
+				// 	if (i <= (zcs - sydlcs)) {
+				// 		cs = '<span class="login-sc login-used login-used" style="width: 8px;height: 8px;display:block;border-radius: 50%;float: left;margin-right: 5px;" time="' + i + '"></span>';
+				// 	} else {
+				// 		cs = '<span class="login-sc login-used login-unused" style="width: 8px;height: 8px;display: block;border-radius: 50%;float: left;margin-right: 5px;" time="' + i + '"></span>';
+				// 	}
+				// 	console.log(cs);
+					
+				// }
+				this.errInfo.time = sydlcs;
+				this.errInfo.allTime = zcs;
+				this.errInfo.tip = msg;
+				this.errInfo.status = true;
+
+				if (sydlcs == zcs) {
+					this.errInfo.status = false;
+				}
+
+				if (0 >= sydlcs) {
+					this.errInfo.status = true;
+					this.errInfo.time = 0;
+					this.errInfo.allTime = 5;
+					this.errInfo.tip = msg;
+					return false;
+				} else {
+					this.errInfo.status = true;
+					this.errInfo.tip = msg;
+				}
+			},
+			lockScreenFun(){
+				console.log("锁屏点击了1");
+				this.isLockScreen = true;
+				$("#app").css("position", "relative");
+				wd.display.beaconLogin("loginOut");
+				$.ajax({
+					type: 'POST',
+					url: '<ss:serv name='wrLockStat' parm='{"wdConfirmationCaptchaService":"0"}'/>',
+					data: {},
+					async: false,
+					success: function (data) {
+						console.log("成功锁屏");
+						// lock.lockSession(time);
+					},
+				});
+			},
+			unlockSessionByPassword(){
+				console.log("解锁");
+				$("#app").css("position", "");
+				var mm=this.formData.password;
+				if(!mm){
+					this.errInfo.status = true;
+					this.errInfo.tip = "请输入密码";
+					this.errInfo.time = 5;
+					return;
+				}
+				var that = this;
+				$.ajax({
+					url: '<ss:serv name='unlockByPwd' parm='{"wdConfirmationCaptchaService":"0"}'/>',
+					dataType: 'json',
+					type: 'POST',
+					data: {
+						mm: mm,
+					},
+					success: function(data) {
+						// context.target.find('#lock-msg').html(data.msg);
+						if (data.code == -1) {
+							that.showErrorMsg(data.msg, data.sydlcs, data.zcs);
+						}
+						if (data.code == 0) {
+							that.isLockScreen = false;
+							that.formData.password = "";
+							that.errInfo.status = false;
+							that.errInfo.time = 5;
+							that.errInfo.allTime = 5;
+						}
+					},
+				});
+			},
+			changeUser(){
+				console.log('Button clicked!', event);
+			},
+			toggleRight() {
+				this.isRightVisible = !this.isRightVisible;
+				
+				// 清除之前的定时器
+				if (this.hideTimer) {
+					clearTimeout(this.hideTimer);
+				}
+				
+				// 设置新的定时器
+				if (this.isRightVisible) {
+					this.hideTimer = setTimeout(() => {
+					this.isRightVisible = false;
+					}, 10000);
+				}
+			},
+			// 当用户在右侧区域操作时,重置定时器
+			resetTimer() {
+				if (this.hideTimer) {
+					clearTimeout(this.hideTimer);
+				}
+				this.hideTimer = setTimeout(() => {
+					this.isRightVisible = false;
+				}, 10000);
+			}
+          },
+          mounted() {
+			// console.log(window.SS)
+			console.log(window.top.SS)
+
+  			window.top.SS.lockScreenService.init(this);
+            eventBus.subscribe(EVEN_VAR.systemEditModelChange,this.sysEditModelChange);
+            eventBus.subscribe(EVEN_VAR.currentPage, this.currentPageChange);
+			// 监听锁屏
+			// 设置键盘和鼠标事件监听
+			document.addEventListener('keydown', () => {
+              this.setupAutoLock();
+            });
+            
+            document.addEventListener('mousemove', () => {
+              this.setupAutoLock();
+            });
+			this.setupAutoLock();
+
+			<ss:equal val='${empty sessionScope.isLockScreen}' val2='false'>
+				this.lockScreenFun();
+			</ss:equal>
+			this.defaultPersonalPhoto = wd.common.loadSkinFile('image/default-personalPhoto.png');
+			// 如果用户有自定义头像,则使用自定义头像
+			<ss:equal val='${empty sessionScope["ssUser"]["yszwj"]}' val2='false'>
+				<%-- 改。Lin
+				defaultPersonalPhoto="/service?wdService=getData&path=${sessionScope['env.ry']['yszwj']}"; --%>
+				<%--this.defaultPersonalPhoto="/service?wdService=dlByHttp&path=${sessionScope['wd.yyh']['yszwj']}";--%>
+			  this.defaultPersonalPhoto="/service?ssServ=dlByHttp&type=img&path=${sessionScope['ssOrigUser']['yszwj']}";
+			</ss:equal>
+
+			const that = this;
+
+			$.ajax({
+				type: 'POST',
+				
+				url: '<ss:serv name='wrMenuList'/>',
+				async: false,
+				dataType: 'json',
+				success: function (data) {
+					// alert('菜单数据:'+JSON.stringify(data));
+					that.menuData = data;
+
+
+
+					<%-- 测试新UI临时写死 start --%>
+
+					// that.menuData["1"].unshift({
+					// 	desc: "单位",
+					// 	icon: "nav-icon-home",
+					// 	pid:"00001",
+					// 	type:"2",
+					// 	url:'<ss:serv name='dw_cx' dest='objList_bk' parm='{}'/>'
+					// });
+
+					// that.menuData["1"].unshift({
+					// 	desc: "在用单位-部门",
+					// 	icon: "nav-icon-home",
+					// 	pid:"00001",
+					// 	type:"2",
+					// 	url:'<ss:serv name='bm_cx' dest='1objList' parm='{dwid:"101122",ssObjId:"101122",ssObjName:"dw",dataType:"change",ParentViewObject:"dw"}'/>'
+					// });
+
+					// that.menuData["1"].unshift({
+					// 	desc: "人员",
+					// 	icon: "nav-icon-person",
+					// 	pid:"00001",
+					// 	type:"2",
+					// 	url:'<ss:serv name='ry_cx' dest='1ryList' parm='{}'/>'
+					// });
+					<%-- 测试新UI临时写死 end --%>
+
+					that.menuData["1"].unshift({
+						desc: "首页",
+						icon: "icon-shouye",  // v3.0 改为使用新图标库 by xu 20251215
+						pid:"00001",
+						type:"2",
+						url:'/initDesktop?'
+					});
+
+					// v3.0 设置菜单图标 - 使用业务图标库 by xu 20251215
+					that.menuData["1"].forEach(item => {
+						// 一级菜单(文件夹类型)- 有同名二级菜单的用同样图标
+						if(item.id === "1021775") item.icon = "icon-obj-ry";     // 人员
+						if(item.id === "1021812") item.icon = "icon-obj-xy";     // 学员
+						if(item.id === "1021809") item.icon = "icon-biz-grxf";   // 个人消费
+						if(item.id === "1021783") item.icon = "icon-biz-men";    // 门
+						if(item.id === "1021806") item.icon = "icon-caipin";     // 菜品
+						if(item.id === "1021786") item.icon = "icon-biz-rc";     // 日程
+						if(item.id === "1021789") item.icon = "icon-biz-xc";     // 巡查
+						if(item.id === "1021793") item.icon = "icon-biz-kq";     // 考勤
+						if(item.id === "1021795") item.icon = "icon-biz-wp";     // 物品
+						if(item.id === "1021804") item.icon = "icon-biz-cl";     // 车辆
+						// 评价(1021780)、场地(1021800) 暂无图标,使用默认文件夹图标
+
+						// 二级菜单使用对象图标
+						if(item.id === "ry_search") item.icon = "icon-obj-ry";   // 人员
+						if(item.id === "gw_search") item.icon = "icon-obj-gw";   // 岗位
+						if(item.id === "qz_search") item.icon = "icon-obj-qz";   // 群组
+						if(item.id === "dw_search") item.icon = "icon-obj-dw";   // 单位
+						if(item.id === "xy_search") item.icon = "icon-obj-xy";   // 学员
+						if(item.id === "grcz_search") item.icon = "icon-obj-grcz"; // 个人充值
+						if(item.id === "xfj_search") item.icon = "icon-obj-xfj";   // 消费机
+						if(item.id === "jcjl_search") item.icon = "icon-obj-jcjl"; // 进出记录
+						if(item.id === "mjd_search") item.icon = "icon-obj-mjd";   // 门禁点
+						if(item.id === "mtcp_search") item.icon = "icon-mingricaipin"; // 明天菜品
+						if(item.id === "cp_search") item.icon = "icon-caipin";     // 菜品
+						if(item.id === "rc_search") item.icon = "icon-biz-rc";     // 日程
+						if(item.id === "rcjh_search") item.icon = "icon-obj-rcjh"; // 日程计划
+						if(item.id === "xcdjl_search") item.icon = "icon-obj-xcjl"; // 巡查记录
+						if(item.id === "xcd_search") item.icon = "icon-obj-xcd";   // 巡查点
+						if(item.id === "kqjl_search") item.icon = "icon-obj-kqjl"; // 考勤记录
+						if(item.id === "wp_search") item.icon = "icon-biz-wp";     // 物品
+						if(item.id === "cl_search") item.icon = "icon-biz-cl";     // 车辆
+						if(item.id === "cd_search") item.icon = "icon-biz-cd";     // 场地
+					});
+				},
+			});
+
+			// 初始化菜单模式为收起(设置CSS变量)
+			const layoutContainer = document.querySelector('.layout-container');
+			if (layoutContainer) {
+				layoutContainer.style.setProperty('--left-side-width', '60px');
+			}
+          },
+          unmounted() {
+			// 清理定时器和事件监听
+            if(this.autoLockTimer) {
+              clearTimeout(this.autoLockTimer);
+            }
+            document.removeEventListener('keydown', this.setupAutoLock);
+            document.removeEventListener('mousemove', this.setupAutoLock);
+            eventBus.clear(
+              EVEN_VAR.systemEditModelChange,
+              this.sysEditModelChange
+            );
+          },
+        });
+    });
+    </script>
+  </body>
+</html>

+ 217 - 84
skin/easy/css/base.css

@@ -63,9 +63,17 @@
   -webkit-font-smoothing: antialiased;
   -moz-osx-font-smoothing: grayscale;
 }
-/* hover 不改变图标颜色 by xu 20251215 */
+
 
 /* v3.0 菜单图标类 - 文件夹和首页 by xu 20251215 */
+.menu-base-icon {
+  font-family: "icon-base" !important;
+  font-size: 22px;
+  font-style: normal;
+  color: #565d6d;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
 /* 文件夹图标 - 使用旧图标库 iconfont(新库暂无文件夹图标) */
 .icon-folder-open::before {
   content: "\e60c";
@@ -75,11 +83,7 @@
   content: "\e60b";
   font-family: "iconfont" !important;
 }
-/* 首页图标 - 使用基础图标库 icon-base */
-.icon-shouye::before {
-  content: "\e619" !important;
-  font-family: "icon-base" !important;
-}
+
 
 /* 通用icon */
 .common-icon{
@@ -777,9 +781,22 @@ input::placeholder ,textarea::placeholder{
   left: 0;
   width: var(--left-size-width);
   transition: width 0.2s;
-  display: flex;  /* 添加 flex 布局 */
-  flex-direction: column;  /* 垂直排列 */
-  /* 移除容器边框,改为菜单项边框 by xu 20251212 */
+  display: flex;
+  flex-direction: column;
+  /* v3.0 移除容器边框,改为伪元素边框 by xu 20251212 */
+}
+
+/* v3.0 右侧边框线,覆盖整个左侧高度 by xu 20251216 */
+.layout-container .left-side-container::after {
+  content: "";
+  height: 100%;
+  width: 1px;
+  position: absolute;
+  right: 0;
+  top: 0;
+  background: #dadee2;
+  box-shadow: 0px 1px 2px 0px rgba(0, 0, 0, 0.24);
+  z-index: 0;
 }
 
 .layout-container .left-side-container[size="max"] {
@@ -834,15 +851,9 @@ input::placeholder ,textarea::placeholder{
   position: absolute;
   top: 0;
   left: 0;
-  z-index: 100;
+  z-index: 1;
   overflow: hidden;
   background: #fafbfe;
-  
-  /* display: flex;
-  flex-direction: column;
-  justify-content: flex-start;
-  align-items: center; */
-
 }
 
 .layout-container .left-side-content:hover {
@@ -850,17 +861,6 @@ input::placeholder ,textarea::placeholder{
   overflow-y: auto;
 }
 
-.layout-container .left-side-content:after {
-  content: "";
-  height: 100%;
-  width: 1px;
-  position: absolute;
-  left: 100%;
-  top: 0;
-  background: #dadee2;
-  box-shadow: 0px 1px 2px 0px rgba(0, 0, 0, 0.24);
-}
-
 /* ===== 新菜单样式 =====*/
 /* 三种模式控制 */
 .layout-container .left-side-container[data-mode="expand"] {
@@ -888,9 +888,10 @@ input::placeholder ,textarea::placeholder{
 /* 固定区域:顶部(首页) */
 .layout-container .fixed-top {
   flex-shrink: 0;
-  border-bottom: none;  /* 移除直接的 border */
+  border-bottom: none;
   background: #fafbfe;
   position: relative;
+  z-index: 1;
 }
 
 .layout-container .fixed-top::after {
@@ -909,7 +910,9 @@ input::placeholder ,textarea::placeholder{
   flex: 1;
   overflow-y: auto;
   overflow-x: hidden;
-  background: #fafbfe;
+  /* background: #fafbfe; */
+  position: relative;
+  z-index: 1;
 }
 
 /* 滚动条样式 */
@@ -929,9 +932,11 @@ input::placeholder ,textarea::placeholder{
 /* 固定区域:底部(模式按钮) */
 .layout-container .fixed-bottom {
   flex-shrink: 0;
-  border-top: none;  /* 移除上边框 */
-  background: #edf1f5;  /* 背景色 */
+  border-top: none;
+  background: #edf1f5;
   height: 40px;
+  position: relative;
+  z-index: 1;
 }
 
 /* 一级菜单分隔线(使用:after伪类,90%宽度居中) */
@@ -1006,6 +1011,7 @@ input::placeholder ,textarea::placeholder{
   color: #666;
   transition: all 0.3s;
   min-height: 40px;
+  border-right: 2px solid #dadee2;
 }
 
 .layout-container .menu-mode-btn:hover {
@@ -1348,6 +1354,9 @@ input::placeholder ,textarea::placeholder{
   align-items: center;
   flex-shrink: 0;
 }
+.left-side-container .icon-container.icon-qiehuan{
+  padding: 0 !important;
+}
 /* 选中菜单项隐藏右边框 by xu 20251212 */
 .left-side-container .menu-item.active .menu-item-content{
   background: #edf1f5;
@@ -4774,6 +4783,7 @@ input::placeholder ,textarea::placeholder{
 /* 跨对象弹窗结束 */
 
 /* 项目基本信息开始 */
+/* v3.0 SsSubTab组件改造:去掉顶部图片,改为图标+悬浮模式 by xu 20251216 */
 .project-edit-container {
   width: 100%;
   height: 100%;
@@ -4788,23 +4798,52 @@ input::placeholder ,textarea::placeholder{
   height: 100%;
 }
 
+/* v3.0 左侧菜单默认60px收起 by xu 20251216 */
 .project-edit-container .left-side {
-  width: 180px !important;
-  border-right: 1px solid #e2e4ec;
-  background-color: #edf1f5;
+  width: 60px;
+  background-color: #fafbfe;
+  transition: width 0.2s ease;
+  display: flex;
+  flex-direction: column;
+  overflow: hidden;
+  flex-shrink: 0;
+  position: relative;
 }
 
-.project-edit-container .left-side>div {
-  width: 100%;
+/* v3.0 右侧边框线,覆盖整个左侧高度 by xu 20251216 */
+.project-edit-container .left-side::after {
+  content: "";
+  height: 100%;
+  width: 1px;
+  position: absolute;
+  right: 0;
+  top: 0;
+  background: #dadee2;
+  box-shadow: 0px 1px 2px 0px rgba(0, 0, 0, 0.24);
+  z-index: 0;
 }
 
-.project-edit-container .menu-header {
-  height: 120px;
-  border-bottom: 1px solid #d8dae3;
+/* v3.0 展开状态200px by xu 20251216 */
+.project-edit-container .left-side.is-expanded {
+  width: 200px;
+}
+
+/* v3.0 固定模式:始终收起 by xu 20251216 */
+.project-edit-container .left-side[data-mode="fixed"] {
+  width: 60px !important;
+}
+
+.project-edit-container .left-side>div {
+  width: 100%;
+  position: relative;
+  z-index: 1;
 }
 
+/* v3.0 菜单内容区 by xu 20251216 */
 .project-edit-container .menu-content {
-  height: calc(100% - 60px);
+  flex: 1;
+  overflow: hidden;
+  position: relative;
 }
 
 .project-edit-container .menu-content .scroll-view {
@@ -4814,19 +4853,115 @@ input::placeholder ,textarea::placeholder{
   font-size: 18px;
 }
 
+/* v3.0 菜单项样式,参考GlobalMenu by xu 20251216 */
 .project-edit-container .menu-item,
 .project-edit-container .group .menu-item {
-  padding: 20px 12px 20px 30px;
+  height: 60px;
+  width: 100%;
+  box-sizing: border-box;
   cursor: pointer;
   position: relative;
-  color: #333333;
+  color: #565d6d;
   display: flex;
   align-items: center;
+  justify-content: center;
+  gap: 5px;
+  padding: 0 8px;
+  border-right: 2px solid #dadee2;
+}
+
+/* 展开时左对齐 */
+.project-edit-container .left-side.is-expanded .menu-item {
+  justify-content: flex-start;
+}
+
+/* hover效果 */
+.project-edit-container .menu-item:hover {
+  background: #edf1f5;
 }
 
-.project-edit-container .menu-item .arrow{
+/* active效果,隐藏右边框 */
+.project-edit-container .menu-item.active {
+  background: #edf1f5;
+  border-right-color: #edf1f5;
+}
+
+.project-edit-container .menu-item .arrow {
+  margin-left: auto;
+  display: none;
+}
+
+/* v3.0 展开时显示箭头 by xu 20251216 */
+.project-edit-container .left-side.is-expanded .menu-item .arrow {
+  display: block;
+}
+
+/* v3.0 图标容器样式,参考GlobalMenu by xu 20251216 */
+.project-edit-container .icon-container {
+  position: relative;
+  padding: 10px;
+  box-sizing: content-box;
+  width: 24px;
+  height: 24px;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  flex-shrink: 0;
+}
+
+/* v3.0 新增:文字标签,收起时隐藏 by xu 20251216 */
+.project-edit-container .menu-label {
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  font-size: 18px;
+  color: #565d6d;
+  display: none;
+}
+
+/* v3.0 展开时显示文字 by xu 20251216 */
+.project-edit-container .left-side.is-expanded .menu-label {
+  display: block;
+}
+
+/* v3.0 新增:悬浮提示(收起时显示) by xu 20251216 */
+.project-edit-container .menu-tooltip {
   position: absolute;
-  left: 180px;
+  left: calc(100% + 10px);
+  top: 50%;
+  transform: translateY(-50%);
+  background: #393d51;
+  color: #fff;
+  padding: 8px 16px;
+  border-radius: 4px;
+  white-space: nowrap;
+  z-index: 1000;
+  opacity: 0;
+  pointer-events: none;
+  transition: opacity 0.15s ease;
+  font-size: 14px;
+}
+
+/* v3.0 tooltip小三角 by xu 20251216 */
+.project-edit-container .menu-tooltip::before {
+  content: "";
+  position: absolute;
+  left: -6px;
+  top: 50%;
+  transform: translateY(-50%);
+  border: 6px solid transparent;
+  border-right-color: #393d51;
+  border-left: none;
+}
+
+/* v3.0 悬浮显示tooltip by xu 20251216 */
+.project-edit-container .left-side:not(.is-expanded) .menu-item:hover .menu-tooltip {
+  opacity: 1;
+}
+
+/* v3.0 展开时隐藏tooltip by xu 20251216 */
+.project-edit-container .left-side.is-expanded .menu-tooltip {
+  display: none;
 }
 
 .menu-item-point{
@@ -4835,60 +4970,57 @@ input::placeholder ,textarea::placeholder{
   display: block;
   border-radius: 50%;
   background: #666;
-  
-}
-
-.project-edit-container .menu-item>.icon-container,
-.project-edit-container .group .menu-item>.icon-container {
-  margin-left: 10px;
 }
 
+/* 删除旧的底部分割线样式 */
 .project-edit-container .menu-item::after,
 .project-edit-container .group .menu-item::after {
-  content: "";
-  width: calc(100% - 10px * 2);
-  height: 0;
-  display: block;
-  position: absolute;
-  bottom: -1px;
-  left: 10px;
-  border-bottom: 1px solid #d8dae3;
+  display: none;
 }
 
-.project-edit-container .menu-item.active,
-.project-edit-container .group .menu-item.active {
-  background: #fff;
+.project-edit-container .group {
+  width: 100%;
 }
 
-.project-edit-container .menu-item.active::after,
-.project-edit-container .group .menu-item.active::after {
-  border-bottom-color: transparent;
+.project-edit-container .group-detail {
+  background: rgba(0, 0, 0, 0.03);
 }
 
-.project-edit-container .group {
-  width: 100%;
+/* v3.0 子菜单样式 by xu 20251216 */
+.project-edit-container .group-detail .menu-item {
+  padding-left: 20px;
 }
 
-/* .project-edit-container  .group-detail {
-  padding-left: 10px;
-} */
+.project-edit-container .left-side.is-expanded .group-detail .menu-item {
+  padding-left: 50px;
+}
 
-.project-edit-container  .group-detail .menu-item {
-  padding-left: 44px;
+/* v3.0 收起时隐藏子菜单 by xu 20251216 */
+.project-edit-container .left-side:not(.is-expanded) .group-detail {
+  display: none;
 }
 
-/* .project-edit-container .group-detail .menu-item::before {
-  content: "";
-  height: 6px;
-  width: 6px;
-  border-radius: 50%;
-  position: absolute;
-  top: 50%;
-  left: 30px;
-  background: #666;
-  transform: translateY(-50%);
-  position: relative;
-} */
+/* v3.0 新增:模式切换按钮,参考GlobalMenu by xu 20251216 */
+.project-edit-container .menu-mode-toggle {
+  min-height: 40px;
+  width: 100%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  padding: 12px 8px;
+  cursor: pointer;
+  border-top: 1px solid #d8dae3;
+  border-right: 2px solid #dadee2;
+  flex-shrink: 0;
+}
+
+.project-edit-container .menu-mode-toggle:hover {
+  background: rgba(0, 0, 0, 0.05);
+}
+
+.project-edit-container .menu-mode-toggle .icon-container {
+  padding: 0 !important;
+}
 
 .sub-tab-menu-footer {
   height: 60px;
@@ -4954,8 +5086,9 @@ input::placeholder ,textarea::placeholder{
   display: block;
 }
 
+/* v3.0 右侧内容区改为flex:1自适应 by xu 20251216 */
 .project-edit-container>div.content-area {
-  width: calc(100% - 180px);
+  flex: 1;
   overflow-y: auto;
 }
 

+ 3 - 3
skin/easy/css/icon-base/iconfont.css

@@ -1,12 +1,12 @@
 @font-face {
-  font-family: "icon-biz";
+  font-family: "icon-base";
   src: url('../../fonts/icon-base/iconfont.woff2') format('woff2'),
        url('../../fonts/icon-base/iconfont.woff') format('woff'),
        url('../../fonts/icon-base/iconfont.ttf') format('truetype');
 }
 
-.iconfont {
-  font-family: "iconfont" !important;
+.icon-base {
+  font-family: "icon-base" !important;
   font-size: 16px;
   font-style: normal;
   -webkit-font-smoothing: antialiased;

+ 3 - 2
skin/easy/css/icon-biz/iconfont.css

@@ -6,8 +6,9 @@
 }
 
 
-.iconfont {
-  font-family: "iconfont" !important;
+
+.icon-biz {
+  font-family: "icon-biz" !important;
   font-size: 16px;
   font-style: normal;
   -webkit-font-smoothing: antialiased;

+ 6 - 6
skin/easy/css/iconfont.css

@@ -14,13 +14,13 @@
   content: "\e6f2";
 }
 
-.icon-qiehuan_xi:before {
+/* .icon-qiehuan_xi:before {
   content: "\e6f1";
-}
+} */
 
-.icon-qiehuan:before {
+/* .icon-qiehuan:before {
   content: "\e6f0";
-}
+} */
 
 .icon-xunchajilu:before {
   content: "\e6ef";
@@ -354,9 +354,9 @@
   content: "\e68f";
 }
 
-.icon-shouye:before {
+/* .icon-shouye:before {
   content: "\e690";
-}
+} */
 
 .icon-xiazai:before {
   content: "\e691";

BIN
skin/easy/fonts/icon-base/iconfont.ttf


BIN
skin/easy/fonts/icon-base/iconfont.woff


BIN
skin/easy/fonts/icon-base/iconfont.woff2


BIN
skin/easy/fonts/icon-biz/iconfont.ttf


BIN
skin/easy/fonts/icon-biz/iconfont.woff


BIN
skin/easy/fonts/icon-biz/iconfont.woff2