Преглед изворни кода

feat:调整一级查询页

- 没有tab && 没有图表标记,右侧栏不要
- 没有rbarTabNameList里面的rbarObj 不要出现已选tab ,左侧的卡片也不允许选中 包括右下角的hover选中图标
- 右侧tab之间的拖拽失效了
- 右侧添加图、添加表之类的添加按钮(具体服务接口找回旧的里面有),全局右上角的编辑按钮 如果在首页点 就是左侧菜单下面出新增按钮 如果在对象页面 就是右侧栏出新增按钮 然后鼠标移入右侧栏新增按钮hover浮动出两个选项 新增图 新增表 点击打开
* wd.display.showComponent({show:["wdDialog"],url:"<ss:serv name='addPform' parm='{"wdConfirmationCaptchaService":"0","dxm":"${ssObjName}"}' dest='pformSet'/>",title:"设置统计表",width:800,height:580});
* wd.display.showComponent({show:["wdDialog"],url:"<ss:serv name='addPcht' parm='{"wdConfirmationCaptchaService":"0","dxm":"${ssObjName}","use_grtjmbid":"${use_grtjmbid}"}' dest='pchtSet'/>",title:"设置统计图",width:800,height:580});
- 右侧栏图标调整,人员、预定、服务固定用业务对象的 已选、图、表用当前对象菜单的图表
- 已选tab右上角 close图标的样式修改
- miniInfo.jsp 按照 txt 调整
apple пре 1 дан
родитељ
комит
4b72cff8bc

Разлика између датотеке није приказан због своје велике величине
+ 924 - 889
js/vue/ss-components.js


+ 21 - 0
js/vue/ss-index-components.js

@@ -342,6 +342,12 @@ export const GlobalMenu = {
         const onMenuClick = (item) => {
             console.log(item)
             console.log(activeItem.value)
+            // 功能说明:切换菜单时强制退出系统编辑态(避免“编辑态残留”导致左侧加号/标记异常) by xu 20260123
+            try {
+                eventBus.publish(EVEN_VAR.systemEditModelChange, { mode: "read", source: "menu" });
+            } catch (_) {
+                try { eventBus.publish(EVEN_VAR.systemEditModelChange, "read"); } catch (_) {}
+            }
             if(item.component && item.js){
                 eval(item.js)
             } else if(item.component){
@@ -459,6 +465,21 @@ export const GlobalMenu = {
                             ) : []
                         )
                     ]).flat()
+                ]),
+
+                // 功能说明:系统编辑模式(sys-mode="edit")下显示左侧菜单底部“+”入口(由 CSS 变量 --menu-add-btn-display 控制显隐) by xu 20260123
+                Vue.h('div', {
+                    class: ['menu-item', 'add-menu-btn'],
+                    onClick: () => {
+                        try {
+                            eventBus.publish(EVEN_VAR.showProjectDialog);
+                        } catch (_) {
+                        }
+                    }
+                }, [
+                    Vue.h('div', { class: 'add' }, [
+                        Vue.h(SsIcon, { class: 'menu-base-icon icon-add' })
+                    ])
                 ])
                 // v3.0 移除底部切换按钮,功能移至 header 右侧图标 by xu 20251219
             ])

+ 189 - 0
js/vue/tools.js

@@ -201,3 +201,192 @@ export function debounce(func, wait, options) {
     return debounced;
 }
 
+// 功能说明:统一处理后端可能返回的 {val}/{value} 结构,供组件内部字段适配复用 by xu 20260122
+export function normalizeMaybeVal(input) {
+  if (input === undefined || input === null) return input;
+  if (typeof input === "object") {
+    if (Object.prototype.hasOwnProperty.call(input, "val")) return input.val;
+    if (Object.prototype.hasOwnProperty.call(input, "value")) return input.value;
+  }
+  return input;
+}
+
+// 功能说明:缩略图 URL 构建(dlByHttp 直出图片),支持 thn 为字符串或 {val}/{value} by xu 20260122
+export function buildThumbUrl(thn) {
+  const v = normalizeMaybeVal(thn);
+  if (v === undefined || v === null || v === "") return "";
+  return "/service?ssServ=dlByHttp&type=img&path=" + encodeURIComponent(String(v));
+}
+
+// 功能说明:统一按 fmt 动态格式化 {val, fmt}(支持任意组合 yyyy/MM/dd/HH/mm/ss),供卡片 tags/标题复用 by xu 20260122
+export function formatValByFmt(val, fmt) {
+  try {
+    if (!fmt || val === undefined || val === null || val === "") return val;
+    const raw = typeof val === "string"
+      ? val.replace(/[\u202f\u00a0]/g, " ").replace(/ /g, " ").trim()
+      : val;
+    const d = raw instanceof Date ? raw : new Date(raw);
+    if (isNaN(d.getTime())) return val;
+    const pad2 = (n) => String(n).padStart(2, "0");
+    const tokens = {
+      yyyy: String(d.getFullYear()),
+      MM: pad2(d.getMonth() + 1),
+      M: String(d.getMonth() + 1),
+      dd: pad2(d.getDate()),
+      d: String(d.getDate()),
+      HH: pad2(d.getHours()),
+      H: String(d.getHours()),
+      mm: pad2(d.getMinutes()),
+      m: String(d.getMinutes()),
+      ss: pad2(d.getSeconds()),
+      s: String(d.getSeconds()),
+    };
+    const f = String(fmt);
+    if (!/(yyyy|MM|dd|HH|mm|ss|M|d|H|m|s)/.test(f)) return val;
+    return f.replace(/yyyy|MM|dd|HH|mm|ss|M|d|H|m|s/g, (k) => tokens[k] ?? k);
+  } catch (_) {
+    return val;
+  }
+}
+
+// 功能说明:解析 parm/param 参数(兼容 JSON 字符串、qs 字符串、对象) by xu 20260122
+export function parseParmLike(parmOrParam) {
+  if (!parmOrParam) return {};
+  if (typeof parmOrParam === "object") return parmOrParam;
+  if (typeof parmOrParam !== "string") return {};
+  const s = String(parmOrParam).trim();
+  if (!s) return {};
+  // JSON 格式
+  if (s[0] === "{" || s[0] === "[") {
+    try {
+      const obj = JSON.parse(s);
+      if (obj && typeof obj === "object") return obj;
+    } catch (_) {}
+  }
+  // qs 格式(&a=b 或 a=b)
+  return { __rawQs: s };
+}
+
+// 功能说明:追加查询参数到 URL(支持去重、数组值) by xu 20260122
+export function appendQueryParam(url, key, value) {
+  if (!key) return url;
+  if (value === undefined || value === null) return url;
+  const s = String(value);
+  if (s === "") return url;
+  // 检查参数是否已存在
+  const escapeRegExp = (str) => String(str || "").replace(/[.*+?^{}$()|[\]\\]/g, "\\$&");
+  const hasParam = new RegExp("([?&])" + escapeRegExp(key) + "=").test(String(url || ""));
+  if (hasParam) return url;
+  const separator = url.indexOf("?") > -1 ? "&" : "?";
+  return url + separator + encodeURIComponent(String(key)) + "=" + encodeURIComponent(s);
+}
+
+// 功能说明:从搜索字段列表和表单中提取参数(用于透传搜索条件到弹窗) by xu 20260122
+export function pickSearchParams(searchFieldList, form) {
+  const params = {};
+  if (!Array.isArray(searchFieldList) || !form) return params;
+  searchFieldList.forEach((field) => {
+    const key = field && field.name;
+    if (!key) return;
+    const value = form[key];
+    if (value === undefined || value === null) return;
+    if (Array.isArray(value)) {
+      params[key] = value.filter((v) => v !== undefined && v !== null && v !== "");
+    } else if (value !== "") {
+      params[key] = value;
+    }
+  });
+  return params;
+}
+
+// 功能说明:构建服务 URL(统一处理 ssToken/servName+dest+parm 三种模式) by xu 20260122
+export function buildServiceUrl(srv, options = {}) {
+  if (!srv) return "";
+  const { extraParams = {} } = options;
+  let url = "";
+  // 模式1:优先 ssToken
+  const token = String(srv.ssToken || "").trim();
+  if (token) {
+    url = "/service?ssToken=" + encodeURIComponent(token);
+  } else if (srv.servName) {
+    // 模式2:servName + dest + parm
+    url = "/service?ssServ=" + encodeURIComponent(String(srv.servName));
+    if (srv.dest) url += "&ssDest=" + encodeURIComponent(String(srv.dest));
+    // 解析 parm/param
+    const parm = srv.parm !== undefined ? srv.parm : srv.param;
+    const parsed = parseParmLike(parm);
+    if (parsed.__rawQs) {
+      // qs 格式直接拼接
+      const qs = parsed.__rawQs;
+      url += (qs.startsWith("&") ? "" : "&") + qs;
+    } else {
+      // 对象格式遍历拼接
+      Object.entries(parsed).forEach(([k, v]) => {
+        if (v === undefined || v === null) return;
+        url += "&" + encodeURIComponent(k) + "=" + encodeURIComponent(String(v));
+      });
+    }
+  } else if (srv.dest) {
+    // 模式3:仅 dest(报表场景)
+    url = "/service?ssDest=" + encodeURIComponent(String(srv.dest));
+    const parm = srv.parm !== undefined ? srv.parm : srv.param;
+    const parsed = parseParmLike(parm);
+    if (parsed.__rawQs) {
+      const qs = parsed.__rawQs;
+      url += (qs.startsWith("&") ? "" : "&") + qs;
+    } else {
+      Object.entries(parsed).forEach(([k, v]) => {
+        if (v === undefined || v === null) return;
+        url += "&" + encodeURIComponent(k) + "=" + encodeURIComponent(String(v));
+      });
+    }
+  }
+  // 追加额外参数
+  Object.entries(extraParams).forEach(([key, value]) => {
+    if (Array.isArray(value)) {
+      value.forEach((v) => {
+        url = appendQueryParam(url, key, v);
+      });
+    } else {
+      url = appendQueryParam(url, key, value);
+    }
+  });
+  return url;
+}
+
+// 功能说明:打开服务弹窗(统一封装 wd.display.showComponent) by xu 20260122
+export function openServiceDialog(srv, options = {}) {
+  if (!srv) return;
+  const { extraParams = {}, onError = null } = options;
+  const url = buildServiceUrl(srv, { extraParams });
+  if (!url) return;
+  try {
+    window.wd.display.showComponent({
+      show: ["wdDialog"],
+      url,
+      title: srv.title || srv.desc || "",
+      width: srv.width,
+      height: srv.height,
+      minHeight: srv.minHeight,
+      maxHeight: srv.maxHeight,
+      showTitle: srv.showTitle,
+    });
+  } catch (error) {
+    console.error("[openServiceDialog] failed:", error);
+    if (onError) onError(error);
+  }
+}
+
+// 功能说明:全局暴露工具函数,供 JSP 中的 Vue 实例使用 by xu 20260122
+if (typeof window !== "undefined") {
+  window.ssTools = {
+    normalizeMaybeVal,
+    buildThumbUrl,
+    formatValByFmt,
+    parseParmLike,
+    appendQueryParam,
+    pickSearchParams,
+    buildServiceUrl,
+    openServiceDialog,
+  };
+}

+ 9 - 9
page/env/addChk.jsp

@@ -71,7 +71,7 @@
 					<!-- <div ssDragh='{max:490,min:50,lvl:2,pct:60}' > -->
 					
 						<iframe style="border: 1px solid #d2d2d2;box-sizing: border-box;height: 100%;" width="100%" height="100%" frameborder="0"
-								src="<ss:serv name='${info.service}' dest='${info.dest}' parm='${info.param}'/>">
+								src="<ss:serv name='${info.servName}' dest='${info.dest}' parm='${info.parm}'/>">
 						</iframe>
 						
 					<!-- </div> -->
@@ -170,18 +170,18 @@
 						<ss:equal val='${empty agrAdd}' val2='false'> <%-- ="${empty agr}"。Lin --%>
 							<input type="submit" value="同意" id="agree" class="bottom-button"
 			<%-- 再去掉 wd.display.changeFormAction(,改用 <varServ.ss subm="true"。Lin
-				去掉 sfty:"1" 参数,不用了 -- ${agr.service} 里的服务,最终是 "ss.agrTask"
-				原 name="${agr.service}" dest="${agr.dest}"
-									onclick='wd.display.changeFormAction("<ss:serv name='${agr.service}' dest='${agr.dest}' parm='{shid:"${shid}",sfty:"1"}'/>",this);'/> --%>
-									onclick='wd.display.changeFormAction("<ss:serv name='${agrAdd.service}' dest='${agrAdd.dest}' parm='{shid:"${shid}"}'/>",this);'/>
+				去掉 sfty:"1" 参数,不用了 -- ${agr.servName} 里的服务,最终是 "ss.agrTask"
+				原 name="${agr.servName}" dest="${agr.dest}"
+									onclick='wd.display.changeFormAction("<ss:serv name='${agr.servName}' dest='${agr.dest}' parm='{shid:"${shid}",sfty:"1"}'/>",this);'/> --%>
+									onclick='wd.display.changeFormAction("<ss:serv name='${agrAdd.servName}' dest='${agrAdd.dest}' parm='{shid:"${shid}"}'/>",this);'/>
 						</ss:equal>
 						<ss:equal val='${empty rejAdd}' val2='false'> <%-- val="${empty rej}"。Lin --%>
 							<input type="submit" value="退回" id="reject" class="bottom-button"
 			<%-- 再去掉 wd.display.changeFormAction(,改用 <varServ.ss subm="true"。Lin
-				去掉 sfty:"0" 参数,不用了 -- ${agr.service} 里的服务,最终是 "ss.rejTask"
-				原 name="${rej.service}" dest="${rej.dest}"
-									onclick='wd.display.changeFormAction("<ss:serv name='${rej.service}' dest='${rej.dest}' parm='{shid:"${shid}",sfty:"0"}'/>",this);'/> --%>
-									onclick='wd.display.changeFormAction("<ss:serv name='${rejAdd.service}' dest='${rejAdd.dest}' parm='{shid:"${shid}"}'/>",this);'/>
+				去掉 sfty:"0" 参数,不用了 -- ${agr.servName} 里的服务,最终是 "ss.rejTask"
+				原 name="${rej.servName}" dest="${rej.dest}"
+									onclick='wd.display.changeFormAction("<ss:serv name='${rej.servName}' dest='${rej.dest}' parm='{shid:"${shid}",sfty:"0"}'/>",this);'/> --%>
+									onclick='wd.display.changeFormAction("<ss:serv name='${rejAdd.servName}' dest='${rejAdd.dest}' parm='{shid:"${shid}"}'/>",this);'/>
 						</ss:equal>
 			<%--
 						<input type="submit" value="同意" class="bottom-button" onclick="@service{submit:true,name:'check',dest:'sys_info',param:{shid:'${shid}',sfty:'1'}}@"/>

+ 12 - 12
page/env/chgChkTab.jsp

@@ -193,45 +193,45 @@
 								<input type="submit" value="同意" id="agree" class="bottom-button"
 									<%-- 再改,去掉 wd.display.reset(,统一用 <varServ@ss resize="true"。Lin
                                                             onclick='wd.display.reset("dialog",this,
-                                                                "<ss:serv name='${agrRes.service}' dest='${agrRes.dest}' parm='{shid:"${shid}"}'/>",
+                                                                "<ss:serv name='${agrRes.servName}' dest='${agrRes.dest}' parm='{shid:"${shid}"}'/>",
                                                                 this);'/> --%>
-									   onclick='ss.display.reset("dialog",this,"<ss:serv name='${agrRes.service}' dest='${agrRes.dest}' parm='{shid:"${shid}"}'/>",this);'/>
+									   onclick='ss.display.reset("dialog",this,"<ss:serv name='${agrRes.servName}' dest='${agrRes.dest}' parm='{shid:"${shid}"}'/>",this);'/>
 							</ss:equal>
 							<ss:equal val='${empty rejRes}' val2='false'>
 								<input type="submit" value="退回" id="reject" class="bottom-button"
 									<%-- 再改,去掉 wd.display.reset(,统一用 <varServ@ss resize="true"。Lin
                                                             onclick='wd.display.reset("dialog",this,
-                                                                "<ss:serv name='${rejRes.service}' dest='${rejRes.dest}' parm='{shid:"${shid}"}'/>",
+                                                                "<ss:serv name='${rejRes.servName}' dest='${rejRes.dest}' parm='{shid:"${shid}"}'/>",
                                                                 this);'/> --%>
-									   onclick='ss.display.reset("dialog",this,"<ss:serv name='${rejRes.service}' dest='${rejRes.dest}' parm='{shid:"${shid}"}'/>",this);'/>
+									   onclick='ss.display.reset("dialog",this,"<ss:serv name='${rejRes.servName}' dest='${rejRes.dest}' parm='{shid:"${shid}"}'/>",this);'/>
 							</ss:equal>
 							<ss:equal val='${empty agrSus}' val2='false'>
 								<input type="submit" value="同意" id="agree" class="bottom-button"
 									<%-- 再改,去掉 wd.display.reset(,统一用 <varServ@ss resize="true"。Lin
                                                             onclick='wd.display.reset("dialog",this,
-                                                                "<ss:serv name='${agrSus.service}' dest='${agrSus.dest}' parm='{shid:"${shid}"}'/>",this);'/> --%>
-									   onclick='ss.display.reset("dialog",this,"<ss:serv name='${agrSus.service}' dest='${agrSus.dest}' parm='{shid:"${shid}"}'/>",this);'/>
+                                                                "<ss:serv name='${agrSus.servName}' dest='${agrSus.dest}' parm='{shid:"${shid}"}'/>",this);'/> --%>
+									   onclick='ss.display.reset("dialog",this,"<ss:serv name='${agrSus.servName}' dest='${agrSus.dest}' parm='{shid:"${shid}"}'/>",this);'/>
 							</ss:equal>
 							<ss:equal val='${empty rejSus}' val2='false'>
 								<input type="submit" value="退回" id="reject" class="bottom-button"
 									<%-- 再改,去掉 wd.display.reset(,统一用 <varServ@ss resize="true"。Lin
                                                             onclick='wd.display.reset("dialog",this,
-                                                                "<ss:serv name='${rejSus.service}' dest='${rejSus.dest}' parm='{shid:"${shid}"}'/>",this);'/> --%>
-									   onclick='ss.display.reset("dialog",this,"<ss:serv name='${rejSus.service}' dest='${rejSus.dest}' parm='{shid:"${shid}"}'/>",this);'/>
+                                                                "<ss:serv name='${rejSus.servName}' dest='${rejSus.dest}' parm='{shid:"${shid}"}'/>",this);'/> --%>
+									   onclick='ss.display.reset("dialog",this,"<ss:serv name='${rejSus.servName}' dest='${rejSus.dest}' parm='{shid:"${shid}"}'/>",this);'/>
 							</ss:equal>
 							<ss:equal val='${empty agrChg}' val2='false'>
 								<input type="submit" value="同意" id="agree" class="bottom-button"
 									<%-- 再改,去掉 wd.display.reset(,统一用 <varServ@ss resize="true"。Lin
                                                             onclick='wd.display.reset("dialog",this,
-                                                                "<ss:serv name='${agrChg.service}' dest='${agrChg.dest}' parm='{shid:"${shid}"}'/>",this);'/> --%>
-									   onclick='ss.display.reset("dialog",this,"<ss:serv name='${agrChg.service}' dest='${agrChg.dest}' parm='{shid:"${shid}"}'/>",this);'/>
+                                                                "<ss:serv name='${agrChg.servName}' dest='${agrChg.dest}' parm='{shid:"${shid}"}'/>",this);'/> --%>
+									   onclick='ss.display.reset("dialog",this,"<ss:serv name='${agrChg.servName}' dest='${agrChg.dest}' parm='{shid:"${shid}"}'/>",this);'/>
 							</ss:equal>
 							<ss:equal val='${empty rejChg}' val2='false'>
 								<input type="submit" value="退回" id="reject" class="bottom-button"
 									<%-- 再改,去掉 wd.display.reset(,统一用 <varServ@ss resize="true"。Lin
                                                             onclick='wd.display.reset("dialog",this,
-                                                                "<ss:serv name='${rejChg.service}' dest='${rejChg.dest}' parm='{shid:"${shid}"}'/>",this);'/> --%>
-									   onclick='ss.display.reset("dialog",this,"<ss:serv name='${rejChg.service}' dest='${rejChg.dest}' parm='{shid:"${shid}"}'/>",this);'/>
+                                                                "<ss:serv name='${rejChg.servName}' dest='${rejChg.dest}' parm='{shid:"${shid}"}'/>",this);'/> --%>
+									   onclick='ss.display.reset("dialog",this,"<ss:serv name='${rejChg.servName}' dest='${rejChg.dest}' parm='{shid:"${shid}"}'/>",this);'/>
 							</ss:equal>
 							<%--
                             <input type="button" value="同意" class="bottom-button" onclick="@service{submit:true,reset:'dialog',name:'check',dest:'sys_info',param:{shid:'${shid}',sfty:'1'}}@" />

+ 23 - 93
page/env/cobjList.jsp

@@ -110,7 +110,7 @@
                     var win=wd.topWindow.dhxWins.window(wdDialogId);
                     win.button("wdBatchPrint").show();
                     win.button("wdBatchPrint").onclick=function(){
-                        <varServ@ss dlg="true" name="${prt.service}" dest="${prt.dest}" parm="${prt.param}" title="${prt.title}" width="${prt.width}" height="${prt.height}" minHeight="${prt.minHeight}" maxHeight="${prt.maxHeight}"/>
+                        <varServ@ss dlg="true" name="${prt.servName}" dest="${prt.dest}" parm="${prt.parm}" title="${prt.title}" width="${prt.width}" height="${prt.height}" minHeight="${prt.minHeight}" maxHeight="${prt.maxHeight}"/>
                     }
                 }catch(e){
                     console.log(e);
@@ -128,7 +128,7 @@
 <body>
 <div id="app">
     <form class="page-container" id="myForm"
-          action="<ss:serv name='${currentService.service}' dest='${currentService.dest}' parm='${currentService.param}'/>"
+          action="<ss:serv name='${currentService.servName}' dest='${currentService.dest}' parm='${currentService.parm}'/>"
           method="post">
         <input type="hidden" name="isAnd" value='${isAnd}'/>
         <input name="management" type="hidden" value="${management}"/>
@@ -153,7 +153,7 @@
                                     :opt="searchFieldOptMap[f.name] || []"
                                     :placeholder="f.desc || ''"
                                     width="120"
-                                    :inp="true"
+                                    inp="true"
                                     url="/service?ssServ=loadObjpOpt&objectpickerdropdown1=1"
                                     :cb="f.cbName"
                             ></ss-objp>
@@ -355,16 +355,16 @@
                     <ss:rpt name='buttonList' id='button'>
                         <ss:equal val='${dataType}'
                                   valList='normal,update,change,bdplay'> <%-- 增加,查看时隐去管理按钮。原来会去掉管理按钮,不知在哪去掉的???Lin --%>
-                            <ss:auth serv='${button.service}'>
+                            <ss:auth serv='${button.servName}'>
                                 <ss:equal val='${empty button.pluginList}' val2='true'>
                                     <%--<input type="button" name="${button.name}" value="${button.buttonName}" class="content-button"
-                                        onclick='wd.display.showComponent({show:["wdDialog"],url:"<ss:serv name='${button.service}' dest='${button.dest}' parm='${button.param}'/>",title:"${button.title}",width:"${button.width}",height:"${button.height}",minHeight:"${button.minHeight}",maxHeight:"${button.maxHeight}",showTitle:"${button.showTitle}"});'/>--%>
+                                        onclick='wd.display.showComponent({show:["wdDialog"],url:"<ss:serv name='${button.servName}' dest='${button.dest}' parm='${button.parm}'/>",title:"${button.title}",width:"${button.width}",height:"${button.height}",minHeight:"${button.minHeight}",maxHeight:"${button.maxHeight}",showTitle:"${button.showTitle}"});'/>--%>
 
                                     <script>
                                         function ${button.id}handleClick() {
                                             wd.display.showComponent({
                                                 show: ["wdDialog"],
-                                                url: "<ss:serv name='${button.service}' dest='${button.dest}' parm='${button.param}'/>",
+                                                url: "<ss:serv name='${button.servName}' dest='${button.dest}' parm='${button.parm}'/>",
                                                 title: "${button.title}",
                                                 width: "${button.width}",
                                                 height: "${button.height}",
@@ -381,7 +381,7 @@
                                             onclick: () => {
                                                 wd.display.showComponent({
                                                     show: ["wdDialog"],
-                                                    url: "<ss:serv name='${button.service}' dest='${button.dest}' parm='${button.param}'/>",
+                                                    url: "<ss:serv name='${button.servName}' dest='${button.dest}' parm='${button.parm}'/>",
                                                     title: "${button.title}",
                                                     width: "${button.width}",
                                                     height: "${button.height}",
@@ -404,7 +404,7 @@
                                 <ss:equal val='${empty button.pluginList}' val2='false'>
                                     <ss:rpt name='${button.pluginList}' id='plugin'>
                                         <%--<span style="display:none;" class="${button.id}children" value="${plugin.plugin.desc}"
-                                            onclick='wd.display.showComponent({show:["wdDialog"],url:"<ss:serv name='${plugin.service}' dest='${plugin.dest}' parm='${plugin.param}'/>",title:"${plugin.title}",width:"${plugin.width}",height:"${plugin.height}",minHeight:"${plugin.minHeight}",maxHeight:"${plugin.maxHeight}",showTitle:"${plugin.showTitle}"});'>
+                                            onclick='wd.display.showComponent({show:["wdDialog"],url:"<ss:serv name='${plugin.servName}' dest='${plugin.dest}' parm='${plugin.parm}'/>",title:"${plugin.title}",width:"${plugin.width}",height:"${plugin.height}",minHeight:"${plugin.minHeight}",maxHeight:"${plugin.maxHeight}",showTitle:"${plugin.showTitle}"});'>
                                         </span>
                                     </ss:rpt>
                                     <input type="button" id="${button.id}" name="${button.name}" value="${button.buttonName}" class="content-button" onclick='void(0)'/>
@@ -424,7 +424,7 @@
                                         function ${button.id}handleClick() {
                                             wd.display.showComponent({
                                                 show: ["wdDialog"],
-                                                url: "<ss:serv name='${plugin.service}' dest='${plugin.dest}' parm='${plugin.param}'/>",
+                                                url: "<ss:serv name='${plugin.servName}' dest='${plugin.dest}' parm='${plugin.parm}'/>",
                                                 title: "${plugin.title}",
                                                 width: "${plugin.width}",
                                                 height: "${plugin.height}",
@@ -439,7 +439,7 @@
                                             onclick: () => {
                                                 wd.display.showComponent({
                                                     show: ["wdDialog"],
-                                                    url: "<ss:serv name='${plugin.service}' dest='${plugin.dest}' parm='${plugin.param}'/>",
+                                                    url: "<ss:serv name='${plugin.servName}' dest='${plugin.dest}' parm='${plugin.parm}'/>",
                                                     title: "${plugin.title}",
                                                     width: "${plugin.width}",
                                                     height: "${plugin.height}",
@@ -460,7 +460,7 @@
                                                 callback: function () {
                                                     wd.display.showComponent({
                                                         show: ["wdDialog"],
-                                                        url: "<ss:serv name='${plugin.service}' dest='${plugin.dest}' parm='${plugin.param}'/>",
+                                                        url: "<ss:serv name='${plugin.servName}' dest='${plugin.dest}' parm='${plugin.parm}'/>",
                                                         title: "${plugin.title}",
                                                         width: "${plugin.width}",
                                                         height: "${plugin.height}",
@@ -615,7 +615,7 @@
                 item.onclick = function () {
                     wd.display.showComponent({
                         show: ["wdDialog"],
-                        url: "<ss:serv name='${item.service.play.service}' dest='${item.service.play.dest}' parm='${item.service.play.param}'/>",
+                        url: "<ss:serv name='${item.service.play.servName}' dest='${item.service.play.dest}' parm='${item.service.play.parm}'/>",
                         title: "${item.service.play.title}",
                         width: "${item.service.play.width}",
                         height: "${item.service.play.height}",
@@ -628,7 +628,7 @@
                 item.onclick = function () {
                     wd.display.showComponent({
                         show: ["wdDialog"],
-                        url: "<ss:serv name='${item.service.update.service}' dest='${item.service.update.dest}' parm='${item.service.update.param}'/>",
+                        url: "<ss:serv name='${item.service.update.servName}' dest='${item.service.update.dest}' parm='${item.service.update.parm}'/>",
                         title: "${item.service.update.title}",
                         width: "${item.service.update.width}",
                         height: "${item.service.update.height}",
@@ -641,7 +641,7 @@
                 item.onclick = function () {
                     wd.display.showComponent({
                         show: ["wdDialog"],
-                        url: "<ss:serv name='${item.service.change.service}' dest='${item.service.change.dest}' parm='${item.service.change.param}'/>",
+                        url: "<ss:serv name='${item.service.change.servName}' dest='${item.service.change.dest}' parm='${item.service.change.parm}'/>",
                         title: "${item.service.change.title}",
                         width: "${item.service.change.width}",
                         height: "${item.service.change.height}",
@@ -817,7 +817,7 @@
                         onclick: () => {
                             wd.display.showComponent({
                                 show: ["wdDialog"],
-                                url: "<ss:serv name='${btn.service}' dest='${btn.dest}' parm='${btn.param}'/>",
+                                url: "<ss:serv name='${btn.servName}' dest='${btn.dest}' parm='${btn.parm}'/>",
                                 title: "${btn.title}",
                                 width: "${btn.width}",
                                 height: "${btn.height}",
@@ -860,7 +860,7 @@
                 item.onclick = function () {
                     wd.display.showComponent({
                         show: ["wdDialog"],
-                        url: "<ss:serv name='${item.service.play.service}' dest='${item.service.play.dest}' parm='${item.service.play.param}'/>",
+                        url: "<ss:serv name='${item.service.play.servName}' dest='${item.service.play.dest}' parm='${item.service.play.parm}'/>",
                         title: "${item.service.play.title}",
                         width: ((${item.service.play.width}+DOM_SIZE_objInfoTabWidth) + ""),
                         height: "${item.service.play.height}",
@@ -961,7 +961,7 @@
                             <%-- 下面的宽度width,如果是变动,则加上选项卡宽度 Ben(20251214) --%>
                             wd.display.showComponent({
                                 show: ["wdDialog"],
-                                url: "<ss:serv name='${item.service.change.service}' dest='${item.service.change.dest}' parm='${item.service.change.param}'/>",
+                                url: "<ss:serv name='${item.service.change.servName}' dest='${item.service.change.dest}' parm='${item.service.change.parm}'/>",
                                 title: "${item.service.change.title}",
                                 width: ((${item.service.change.width}+${'chg'==item.service.change.function.name?'DOM_SIZE_objInfoTabWidth':'0'}) + ""),
                                 height: "${item.service.change.height}",
@@ -982,7 +982,7 @@
                         onclick: () => {
                             wd.display.showComponent({
                                 show: ["wdDialog"],
-                                url: "<ss:serv name='${item.service.update.service}' dest='${item.service.update.dest}' parm='${item.service.update.param}'/>",
+                                url: "<ss:serv name='${item.service.update.servName}' dest='${item.service.update.dest}' parm='${item.service.update.parm}'/>",
                                 title: "${item.service.update.title}",
                                 width: ((${item.service.update.width}+DOM_SIZE_objInfoTabWidth) + ""),
                                 height: "${item.service.update.height}",
@@ -1429,44 +1429,12 @@
                             }
                         }
 
-                        function formatValByFmt(val, fmt) {
-                            if (!fmt) return String(val == null ? "" : val);
-                            var d = toDate(val);
-                            if (!d) return String(val == null ? "" : val);
-                            var yyyy = String(d.getFullYear());
-                            var MM = pad2(d.getMonth() + 1);
-                            var dd = pad2(d.getDate());
-                            var HH = pad2(d.getHours());
-                            var mm = pad2(d.getMinutes());
-                            var ss = pad2(d.getSeconds());
-                            var map = {
-                                "yyyy": yyyy,
-                                "MM": MM,
-                                "dd": dd,
-                                "HH": HH,
-                                "mm": mm,
-                                "ss": ss,
-                                "M": String(d.getMonth() + 1),
-                                "d": String(d.getDate()),
-                                "H": String(d.getHours()),
-                                "m": String(d.getMinutes()),
-                                "s": String(d.getSeconds()),
-                            };
-                            var out = String(fmt);
-                            Object.keys(map).sort(function (a, b) {
-                                return b.length - a.length;
-                            }).forEach(function (k) {
-                                out = out.split(k).join(map[k]);
-                            });
-                            return out;
-                        }
-
                         function normalizeVal(v) {
                             if (v === undefined || v === null) return "";
                             if (typeof v === "string" || typeof v === "number" || typeof v === "boolean") return String(v);
                             if (typeof v === "object") {
                                 if (v.val != null) {
-                                    if (v.fmt) return formatValByFmt(v.val, v.fmt);
+                                    if (v.fmt) return window.ssTools.formatValByFmt(v.val, v.fmt);
                                     return String(v.val);
                                 }
                             }
@@ -1490,7 +1458,7 @@
                             // 功能说明:thn 不为空 => 有图片(否则组件按 thumbType 显示占位 icon);URL 走 dlByHttp by xu 20260115
                             try {
                                 var thn = raw && raw.thn;
-                                if (thn) card.thumb = self.buildThumbUrl(thn);
+                                if (thn) card.thumb = window.ssTools.buildThumbUrl(thn);
                             } catch (e) {
                             }
                             // 功能说明:二级对象卡片标签:由 catList(desc/val) 映射到组件 item.tags(key:desc, value:val) by xu 20260115
@@ -1501,7 +1469,7 @@
                                     if (!c || typeof c !== "object") return null;
                                     var k = c.desc != null ? String(c.desc) : "";
                                     if (!k) return null;
-                                    var v = c.fmt ? formatValByFmt(c.val, c.fmt) : normalizeVal(c.val);
+                                    var v = c.fmt ? window.ssTools.formatValByFmt(c.val, c.fmt) : normalizeVal(c.val);
                                     var o = {};
                                     o[k] = v;
                                     return o;
@@ -1534,16 +1502,6 @@
                         this.listConfig = Object.assign({}, this.listConfig);
                     },
                     // 功能说明:缩略图 URL 构建(参考 objList:dlByHttp 直出图片) by xu 20260115
-                    buildThumbUrl(thn) {
-                        if (!thn) return "";
-                        var v = thn;
-                        try {
-                            if (typeof thn === "object" && thn.val != null) v = thn.val;
-                            else if (typeof thn === "object" && thn.value != null) v = thn.value;
-                        } catch (e) {
-                        }
-                        return "/service?ssServ=dlByHttp&type=img&path=" + encodeURIComponent(String(v));
-                    },
                     // 功能说明:拉取 searchFieldList 中 cbName 下拉的 options,并写入 searchFieldOptMap by xu 20260115
                     loadSearchFieldOptions() {
                         var self = this;
@@ -1573,37 +1531,9 @@
                     },
                     // 功能说明:二级对象页面打开服务(兼容 ssToken 与 servName/dest/parm) by xu 20260115
                     openServiceDialog(srv) {
+                        // 功能说明:使用 tools.js 统一封装的 openServiceDialog by xu 20260122
                         if (!srv) return;
-                        var ssToken = srv.ssToken;
-                        var url = "";
-                        if (ssToken) {
-                            url = "/service?ssToken=" + encodeURIComponent(String(ssToken));
-                        } else {
-                            var servName = srv.servName || srv.service;
-                            var dest = srv.dest || "";
-                            var parm = srv.parm || srv.param || "";
-                            url = "/service?ssServ=" + encodeURIComponent(String(servName || ""));
-                            if (dest) url += "&ssDest=" + encodeURIComponent(String(dest));
-                            if (parm) url += "&parm=" + encodeURIComponent(String(parm));
-                        }
-                        try {
-                            console.log("[cobj] openServiceDialog url", url, srv);
-                        } catch (e) {
-                        }
-                        try {
-                            wd.display.showComponent({
-                                show: ["wdDialog"],
-                                url: url,
-                                title: srv.title || srv.desc || "",
-                                width: String(srv.width || 880),
-                                height: String(srv.height || 650),
-                                minHeight: String(srv.minHeight || 100),
-                                maxHeight: String(srv.maxHeight || 800),
-                                showTitle: String(srv.showTitle || false),
-                            });
-                        } catch (e) {
-                            console.log("openServiceDialog failed", e);
-                        }
+                        window.ssTools.openServiceDialog(srv);
                     },
                     handlePageChange({pageNo, rowNumPer, rowNum}) {
                         // 功能说明:二级对象翻页:更新 ssPaging 后重新调用接口刷新列表 by xu 20260115

Разлика између датотеке није приказан због своје велике величине
+ 554 - 398
page/env/objList.jsp


+ 3 - 3
page/env/objPlay.jsp

@@ -56,8 +56,8 @@
 <tab@ss name="info"/> --%>
 <ss:data name='info'/>
 
-<iframe width="100%" height="100%" param='${info.param}' id="iframe" frameborder="0"
-		src="<ss:serv name='${info.service}' dest='${info.dest}' parm='${info.param}'/>">
+<iframe width="100%" height="100%" param='${info.parm}' id="iframe" frameborder="0"
+		src="<ss:serv name='${info.servName}' dest='${info.dest}' parm='${info.parm}'/>">
 </iframe>
 <!-- 
 <div class='bottom-div'>
@@ -161,7 +161,7 @@
 				console.log(win.button("wdPrint"));
 				win.button("wdPrint").show();
 				win.button("wdPrint").onclick=function(){
-					<varServ@ss dlg="true" name="${prt.service}" dest="${prt.dest}" parm="${prt.param}" title="${prt.title}" width="${prt.width}" height="${prt.height}" minHeight="${prt.minHeight}" maxHeight="${prt.maxHeight}"/>
+					<varServ@ss dlg="true" name="${prt.servName}" dest="${prt.dest}" parm="${prt.parm}" title="${prt.title}" width="${prt.width}" height="${prt.height}" minHeight="${prt.minHeight}" maxHeight="${prt.maxHeight}"/>
 				}
 			}catch(e){
 				console.log(e);

+ 60 - 22
page/home.jsp

@@ -60,7 +60,7 @@
   <!-- menu标签输出end -->
 
     <div id="app" >
-		<div class="self-block layout-container" :sys-mode="sysMode" v-show="isLockScreen==false">
+			<div class="self-block layout-container" :sys-mode="sysMode" :sys-mode-source="sysModeSource" v-show="isLockScreen==false"><%-- // 功能说明:透传 sysModeSource(desktop/biz)给 CSS 控制左侧菜单加号显隐 by xu 20260123 --%>
         <div class="header">
 			<global-header :menu-data="menuData[8]" :icon-items="iconItems"></global-header>
         </div>
@@ -302,25 +302,57 @@
             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);
-        }
+			const currentMode = Vue.ref(sysMode.read.key);
+	        const toggoleSysMode = function (key) {
+	            // 功能说明:区分“桌面页(initDesktop)”与“业务页(iframe 内其他页面)”的编辑模式切换,用于排查加号/编辑态联动 by xu 20260123
+	            try {
+	                const iframeEl = document.querySelector(".layout-container iframe.appIframe");
+	                const iframeSrc = iframeEl?.getAttribute?.("src") || iframeEl?.src || "";
+	                const isDesktop = String(iframeSrc || "").indexOf("initDesktop") > -1;
+	                console.log("[sysMode] toggle click", {
+	                    page: isDesktop ? "desktop" : "biz",
+	                    iframeSrc: iframeSrc,
+	                    from: currentMode.value,
+	                });
+	            } catch (_) {}
+	            let newKey = sysMode.edit.key;
+	            if (currentMode.value === sysMode.edit.key) {
+	                newKey = sysMode.read.key;
+					// SYBJCTRL.saveedit(SESSION_STATE); //保存编辑模式
+	            }else{
+	                // 功能说明:只有桌面页才尝试调用 userEdit;业务页场景 userEdit 可能不存在,不能阻断 sysMode 切换 by xu 20260123
+	                try {
+	                    const iframeEl = document.querySelector(".layout-container iframe.appIframe");
+	                    const iframeSrc = iframeEl?.getAttribute?.("src") || iframeEl?.src || "";
+	                    const isDesktop = String(iframeSrc || "").indexOf("initDesktop") > -1;
+	                    const userEdit = wd?.topWindow?.gxhymWindow?.userEdit;
+	                    if (isDesktop && typeof userEdit === "function") {
+	                        userEdit("gr");
+	                        // userEdit("gf"); //打开编辑模式
+	                    } else {
+	                        console.log("[sysMode] skip userEdit", { isDesktop: isDesktop, hasUserEdit: typeof userEdit === "function", iframeSrc: iframeSrc });
+	                    }
+	                } catch (e) {
+	                    try { console.warn("[sysMode] userEdit failed", e); } catch (_) {}
+	                }
+				}
+	            // 设置系统模式
+	            currentMode.value = newKey;
+	            // 功能说明:发布 systemEditModelChange 时携带来源(desktop/biz),用于 CSS 控制左侧菜单加号显隐 by xu 20260123
+	            try {
+	                const iframeEl = document.querySelector(".layout-container iframe.appIframe");
+	                const iframeSrc = iframeEl?.getAttribute?.("src") || iframeEl?.src || "";
+	                const isDesktop = String(iframeSrc || "").indexOf("initDesktop") > -1;
+	                eventBus.publish(EVEN_VAR.systemEditModelChange, { mode: newKey, source: isDesktop ? "desktop" : "biz" });
+	            } catch (_) {
+	                eventBus.publish(EVEN_VAR.systemEditModelChange, newKey);
+	            }
+	        }
         // 调用组件中的初始化方法
         window.SS.dom.initializeFormApp({
           el: "#app",
-          data() {
-            return {
+	          data() {
+	            return {
 				lockTime: sessionStorage.getItem("lockTime") || 15,
 				isLockScreen: ${!empty sessionScope.isLockScreen},
 				isRightVisible: false,
@@ -336,7 +368,8 @@
 					password: "",
 
 				},
-              sysMode: sysMode.read.key,
+	              sysMode: sysMode.read.key,
+	              sysModeSource: "desktop", // 功能说明:系统编辑模式来源(desktop/biz/menu/unknown),用于控制左侧菜单加号显隐 by xu 20260123
               currentPage: "/initDesktop?",
               menuData: {
 				"8": //系统菜单(左上角LOGO下拉出来的菜单)
@@ -372,10 +405,15 @@
                 this.lockScreenFun();
               }, this.lockTime * 60 * 1000);
             },
-            // 编辑模式变化
-            sysEditModelChange(mode) {
-              this.sysMode = mode;
-            },
+	            // 编辑模式变化
+	            sysEditModelChange(payload) {
+	              // 功能说明:兼容旧入参(mode 字符串)与新入参({mode,source}),并同步 currentMode 供 header 按钮显隐 by xu 20260123
+	              const mode = (payload && typeof payload === "object") ? payload.mode : payload;
+	              const source = (payload && typeof payload === "object") ? payload.source : "unknown";
+	              this.sysMode = mode;
+	              this.sysModeSource = source || "unknown";
+	              try { currentMode.value = mode; } catch (_) {}
+	            },
             currentPageChange(page) {
               this.currentPage = "./" + page;
             }, 

+ 5 - 5
page/homep/taskHomep.jsp

@@ -131,7 +131,7 @@ display: -webkit-box;-webkit-box-orient: vertical;-webkit-line-clamp: 1;overflow
 																						</div>
 																						<%--  草稿查看  --%>
 																						<%--
-																						<a title='${item.playService.title}' class="smallButton icon-i"  onclick='wd.display.showComponent({show:["wdDialog"],hide:[],url:"<wd:token  service='${item.playService.service}' dest='${item.playService.dest}' param='${item.playService.param}' test='false'  />",title:"${item.playService.title}",width:${item.playService.width},height:${item.playService.height},minHeight:${item.playService.minHeight},maxHeight:${item.playService.maxHeight}});' ></a>
+																						<a title='${item.playService.title}' class="smallButton icon-i"  onclick='wd.display.showComponent({show:["wdDialog"],hide:[],url:"<wd:token  service='${item.playService.servName}' dest='${item.playService.dest}' param='${item.playService.parm}' test='false'  />",title:"${item.playService.title}",width:${item.playService.width},height:${item.playService.height},minHeight:${item.playService.minHeight},maxHeight:${item.playService.maxHeight}});' ></a>
 																						--%>
 																						<!-- <div class="vLine-dashed" style="float:right;display:inline-block;width:1px;height:30px;margin-top:5px;">
 
@@ -159,7 +159,7 @@ display: -webkit-box;-webkit-box-orient: vertical;-webkit-line-clamp: 1;overflow
 																				 <ss:equal val='${empty item.cservice}' val2='false'> <%-- 改 equal:val1="true" val2="${not empty item.cservice}"。Lin --%>
 																								<%--  主操作:批量审核  --%>
 																				 onclick='if($(window.event.srcElement).is("a,img,span"))return;wd.display.JumpTest({show:["wdDialog"],hide:[],
-																				 url:"<ss:serv name='${item.cservice.service}' dest='${item.cservice.dest}' parm='${item.cservice.param}'/>",
+																				 url:"<ss:serv name='${item.cservice.servName}' dest='${item.cservice.dest}' parm='${item.cservice.parm}'/>",
 																				 title:"${item.cservice.title}",width:${item.cservice.width},height:${item.cservice.height},minHeight:${empty item.cservice.minHeight?'null':item.cservice.minHeight},maxHeight:${empty item.cservice.maxHeight?'null':item.cservice.maxHeight}});event.stopPropagation();console.log(1211)'
 																				 </ss:equal>
 																				>
@@ -199,7 +199,7 @@ display: -webkit-box;-webkit-box-orient: vertical;-webkit-line-clamp: 1;overflow
 																						data-tt-parent-id="db${item.plid}"
 																						</ss:equal>
 																				onclick='wd.display.JumpTest({show:["wdDialog"],hide:[],
-																				url:"<ss:serv name='${item.service.service}' dest='${item.service.dest}' parm='${item.service.param}'/>",
+																				url:"<ss:serv name='${item.service.servName}' dest='${item.service.dest}' parm='${item.service.parm}'/>",
 																				title:"${item.service.title}",width:${item.service.width},height:${item.service.height},minHeight:${empty item.service.minHeight ?'null':item.service.minHeight},maxHeight:${empty item.service.maxHeight?'null':item.service.maxHeight}});event.stopPropagation();'>
 																						<td class="tdBt bb1 aa1" style="padding-left: 15px;width:100%;box-sizing: border-box;">
 																							 <span class="file"></span>
@@ -230,14 +230,14 @@ display: -webkit-box;-webkit-box-orient: vertical;-webkit-line-clamp: 1;overflow
 
 																								<ss:equal val='${empty item.iservice}' val2='false'>
 																										<a class="smallButton icon-i" class="aa shitem" href="javascript:void(0)"
-																								onclick='wd.display.showComponent({show:["wdDialog"],url:"<ss:serv name='${item.iservice.service}' dest='${item.iservice.dest}' parm='${item.iservice.param}'/>",title:"${item.iservice.title}",width:"${item.iservice.width}",height:"${item.iservice.height}",minHeight:"${item.iservice.minHeight}",maxHeight:"${item.iservice.maxHeight}"});'
+																								onclick='wd.display.showComponent({show:["wdDialog"],url:"<ss:serv name='${item.iservice.servName}' dest='${item.iservice.dest}' parm='${item.iservice.parm}'/>",title:"${item.iservice.title}",width:"${item.iservice.width}",height:"${item.iservice.height}",minHeight:"${item.iservice.minHeight}",maxHeight:"${item.iservice.maxHeight}"});'
 																								event.stopPropagation();
 																										>
 																										</a>
 																								</ss:equal>
 																								<ss:equal val='${empty item.p_iservice}' val2='false'> <%-- 改 equal:val1="true" val2="${not empty item.p_iservice}"。Lin --%>
 																										<a  class="smallButton icon-bigI" style="margin-right: 6px;" class="aa shitem" href="javascript:void(0)"
-																										onclick='wd.display.showComponent({show:["wdDialog"],url:"<ss:serv name='${item.p_iservice.service}' dest='${item.p_iservice.dest}' parm='${item.p_iservice.param}'/>",title:"${item.p_iservice.title}",width:"${item.p_iservice.width}",height:"${item.p_iservice.height}",minHeight:"${item.p_iservice.minHeight}",maxHeight:"${item.p_iservice.maxHeight}"});'
+																										onclick='wd.display.showComponent({show:["wdDialog"],url:"<ss:serv name='${item.p_iservice.servName}' dest='${item.p_iservice.dest}' parm='${item.p_iservice.parm}'/>",title:"${item.p_iservice.title}",width:"${item.p_iservice.width}",height:"${item.p_iservice.height}",minHeight:"${item.p_iservice.minHeight}",maxHeight:"${item.p_iservice.maxHeight}"});'
 																										event.stopPropagation();
 																										>
 

+ 117 - 5
skin/easy/css/base.css

@@ -5,8 +5,8 @@
 
 /* 证件照 */
 .id-photo{
-  width: 153px;
-  height: 213px;
+  width: 68px;
+  height: 100px;
   background: #e8e8e8;
   background-size: cover;
   cursor: pointer;
@@ -35,8 +35,8 @@
 }
 /* 生活照 */
 .life-photo{
-  width: 144px;
-  height: 144px;
+  width: 94px;
+  height: 94px;
   border-radius: 50%;
   background:#e8e8e8;
   background-size: contain;
@@ -1934,6 +1934,18 @@ input::placeholder ,textarea::placeholder{
   justify-content: center;
 }
 
+/* 功能说明:卡片右上角状态图标组(不使用 menu-*,便于统一 hover/active 扩展) by xu 20260123 */
+.knowledge-item-container .card-status-icons .status-icon.ss-card-status-biz-icon{
+  font-family: "icon-biz" !important;
+  font-size: 24px;
+  color: #4d4d4d;
+}
+.knowledge-item-container .card-status-icons .status-icon.ss-card-status-base-icon{
+  font-family: "icon-base" !important;
+  font-size: 24px;
+  color: #4d4d4d;
+}
+
 .knowledge-item-container .header:hover {
   --header-color: #fff;
   background: #575d6d;
@@ -1945,6 +1957,69 @@ input::placeholder ,textarea::placeholder{
   padding: 22px 20px 8px;
 }
 
+/* 功能说明:业务页 objList 编辑态右下角“新增(+)"入口(hover 上拉菜单:增加图/增加表) by xu 20260123 */
+.ss-objlist-fab{
+  position: fixed;
+  /* 功能说明:业务页在 iframe 内 fixed 参考的是 iframe 视口,默认向上抬高避免遮挡 by xu 20260123 */
+  right: var(--ss-objlist-fab-right, 24px);
+  bottom: var(--ss-objlist-fab-bottom, 90px);
+  z-index: 2000;
+  display: flex;
+  flex-direction: column-reverse; /* 功能说明:菜单在上、按钮在下(向上拉出) by xu 20260123 */
+  align-items: flex-end;
+  gap: 0;
+}
+.ss-objlist-fab__btn{
+  /* 功能说明:新增按钮样式参考左侧菜单 .left-side-container .add by xu 20260123 */
+  width: 45px;
+  height: 45px;
+  border-radius: 5px;
+  border: none;
+  background: #ffffff;
+  box-shadow: 0 1px 4px #ccc;
+  cursor: pointer;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+.ss-objlist-fab__btn:hover{
+  background: #ffffff;
+}
+.ss-objlist-fab__btn .icon-container{
+  font-size: 22px; /* 功能说明:新增按钮图标大小与左侧菜单一致 by xu 20260123 */
+}
+.ss-objlist-fab__menu{
+  /* 功能说明:上拉菜单样式参考左侧深色菜单浮层,且可移入点击不闪退 by xu 20260123 */
+  display: none;
+  min-width: 140px;
+  background: #393d51;
+  border-radius: 10px;
+  box-shadow: 0 10px 26px rgba(0,0,0,.18);
+  padding: 6px 0;
+  pointer-events: auto;
+  margin-bottom: 6px;
+}
+/* 功能说明:用容器 hover 保持菜单显示(菜单在正常流里,鼠标可穿越间隙进入菜单) by xu 20260123 */
+.ss-objlist-fab:hover .ss-objlist-fab__menu{
+  display: block;
+}
+.ss-objlist-fab__item{
+  padding: 8px 16px;
+  border-radius: 0;
+  color: #d8d8d8;
+  font-size: 14px;
+  cursor: pointer;
+  user-select: none;
+  border-bottom: 1px solid #303445;
+}
+.ss-objlist-fab__item:last-child{
+  border-bottom: none;
+}
+.ss-objlist-fab__item:hover{
+  background: #fffdfd;
+  color: #333;
+}
+
 .knowledge-item-container .box-header>div:first-child {
   color: #000000; /* 修改为纯黑色 by xu 20260105 */
   font-size: 20px;
@@ -1982,9 +2057,10 @@ input::placeholder ,textarea::placeholder{
 
 /* 证件照尺寸,高度100px,宽度按比例73px by xu 20260105 */
 .knowledge-item-container.card-photo .left {
-  width: 73px !important;
+  width: 68px !important;
   height: 100px !important;
   border: 1px solid #dddfe6;
+  box-sizing: border-box;
 }
 
 /* 缩略图尺寸固定为 180×100px by xu 20260105 */
@@ -5067,6 +5143,23 @@ input::placeholder ,textarea::placeholder{
   min-height: 0;
   user-select: text;
 }
+/* 功能说明:右侧栏专用图标基类(避免复用左侧菜单 menu-icon/menu-base-icon) by xu 20260123 */
+.ss-sidebar-biz-icon{
+  font-family: "icon-biz" !important;
+  font-size: 18px;
+  color: #4d4d4d;
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+.ss-sidebar-base-icon{
+  font-family: "icon-base" !important;
+  font-size: 16px;
+  color: #cbced2;
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
 .ss-sidebar__inner{
   /* 功能说明:暂时回退为固定底部留白(避免底部区域遮挡内容) by xu 20260115 */
   padding: 0 10px 96px;
@@ -5137,6 +5230,8 @@ input::placeholder ,textarea::placeholder{
   height: 6px;
   background: transparent;
   cursor: row-resize;
+  touch-action: none; /* 功能说明:禁用默认滚动手势,确保 pointermove 能用于拖拽调高度 by xu 20260122 */
+  user-select: none; /* 功能说明:拖拽时避免选中文本导致手势中断 by xu 20260122 */
 }
 .ss-sidebar-gap.is-active{
   background: #d8dae1; /* 长按约0.5s进入拖拽态才变色 by xu 20260106 */
@@ -5432,6 +5527,23 @@ input::placeholder ,textarea::placeholder{
 .ss-sidebar-header-btn .icon-container{
   font-size: 16px;
 }
+/* 功能说明:右侧栏“已选”清空按钮样式特殊处理——35*35 贴右侧、默认无边框无背景;hover 变底色且图标变白 by xu 20260122 */
+.ss-sidebar-panel__tools .ss-sidebar-header-btn{
+  width: 35px;
+  height: 35px;
+  border: none;
+  background: transparent;
+  border-radius: 0;
+  margin-right: -8px; /* 功能说明:抵消 header 的 padding-right=8px,让按钮贴右侧 by xu 20260122 */
+}
+.ss-sidebar-panel__tools .ss-sidebar-header-btn:hover{
+  border: none;
+  background: #393d51;
+  color: #fff;
+}
+.ss-sidebar-panel__tools .ss-sidebar-header-btn:hover .icon-container{
+  color: #fff;
+}
 .ss-sidebar-item-btn{
   /* item 操作按钮区域:48x48,默认无背景/无边框 by xu 20260106 */
   width: 48px;

+ 20 - 0
skin/easy/css/icon-biz/iconfont.css

@@ -13,6 +13,26 @@
   -moz-osx-font-smoothing: grayscale;
 }
 
+.icon-obj-qj:before {
+  content: "\e670";
+}
+
+.icon-obj-wxz:before {
+  content: "\e66d";
+}
+
+.icon-obj-qjz:before {
+  content: "\e66e";
+}
+
+.icon-obj-fw:before {
+  content: "\e66f";
+}
+
+.icon-obj-jtcy:before {
+  content: "\e66c";
+}
+
 .icon-obj-xiaoq:before {
   content: "\e66b";
 }

+ 3 - 1
skin/easy/css/iconfont.css

@@ -1,6 +1,9 @@
 @font-face {
   font-family: "iconfont"; /* Project id 4810824 */
+  /* // 功能说明:修复 v2 iconfont @font-face src 语法并补全 woff/ttf 回退 by xu 20260123 */
   src: url('../fonts/iconfont.woff2') format('woff2'),
+       url('../fonts/iconfont.woff') format('woff'),
+       url('../fonts/iconfont.ttf') format('truetype');
 }
 .iconfont {
   font-family: "iconfont" !important;
@@ -981,4 +984,3 @@
 .icon-wenjianjia-kai:before {
   content: "\e60c";
 }
-

+ 2 - 2
skin/easy/css/var.css

@@ -18,7 +18,7 @@ html{
 --menu-item-label-visible: visible;
 --menu-item-label-opacity: 1;
 }
-.layout-container[sys-mode="edit"] {
+.layout-container[sys-mode="edit"][sys-mode-source="desktop"] { /* 功能说明:仅“桌面页编辑态”显示左侧菜单底部加号(业务页编辑不显示) by xu 20260123 */
 --menu-add-btn-display: flex;
 --menu-edit-mark-display: block;
 }
@@ -33,4 +33,4 @@ html{
     -ms-user-select: none;
     user-select: none;
   }
-  
+  

BIN
skin/easy/fonts/.smbdeleteAAAa00000012eea9


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


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


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


+ 9 - 8
skin/easy/main.css

@@ -763,12 +763,12 @@ border-radius: 4px;
 }
 
 /*增加*/
-.icon-add {
+/* .icon-add {
     background-image: url(image/svg_icon/xinzeng.svg);
     background-position-x: center;
     background-repeat: no-repeat;
     background-size: 40%;
-}
+} */
 
 input.icon-add {
     width: 22px;
@@ -4674,8 +4674,8 @@ table.list {
 /*--------------------------------------照片样式----------------------------------------------------*/
 /* 工作照 */
 .photo {
-    width: 102px;
-    height: 142px;
+    width: 68px;
+    height: 100px;
     border: 1px solid #cccccc;
     display: flex;
     justify-content: center;
@@ -4686,14 +4686,14 @@ table.list {
 }
 
 .photo img {
-    max-height: 100%;
-    max-width: 100%;
+    height: 100%;
+    /* width: 100%; */
 }
 
 /*个性照*/
 .personalPhoto {
-    width: 100px;
-    height: 100px;
+    width: 94px;
+    height: 94px;
     border: 1px solid #cccccc;
     display: flex;
     justify-content: center;
@@ -4702,6 +4702,7 @@ table.list {
     overflow: hidden;
     border-radius: 50%;
     background: #fff;
+    margin-top: 5px !important;
 }
 
 .personalPhoto img {

+ 26 - 26
ss/clip/miniInfo.jsp

@@ -2,9 +2,9 @@
 <div class="longCardList-div" style="box-sizing: border-box;">
 	<table class="scrollbar" style="max-height: 100%;width: 100%;">
 		<tbody style="width: 100%;padding: 0px 16px 0px 11px;box-sizing: border-box;"> <%-- 去掉 id="wdTbody0",好像没用到。Lin --%>
-		<ss:rpt name='objectList' id='item'>
+		<ss:rpt name='objList' id='item'>
 			<tr
-					<ss:equal val='${item.service.state}' val2='0'>
+					<ss:equal val='${item.rauth}' val2='0'>
 						class="xxxfilter"
 <%-- 再改为 WebC.REQ_objName、WebC.REQ_objId,避免与数据表里的 对象名、对象ID 字段重名。Lin
 						onClick='wd.display.showComponent({show:["wdDialog"],url:"<ss@serv name='ydsq_tj' parm='{"dxid":"${item.dxid}","wdConfirmationCaptchaService":"0","dxm":"${item.dxm}"}' dest='ydsq_tj'/>",title:"借阅",width:613,height:387});' --%>
@@ -12,44 +12,44 @@
 					</ss:equal>
 				>
 				<td class="hLine"
-						<ss:equal val='${empty item.service.play}' val2='false'>
-							titlexxx="${item.service.play.title}"
-							onclick='wd.display.showComponent({show:["wdDialog"],url:"<ss:serv name='${item.service.play.service}' dest='${item.service.play.dest}' parm='${item.service.play.param}'/>",title:"${item.service.play.title}",width:"${item.service.play.width}",height:"${item.service.play.height}",minHeight:"${item.service.play.minHeight}",maxHeight:"${item.service.play.maxHeight}"});'
+						<ss:equal val='${empty item.play}' val2='false'>
+							titlexxx="${item.play.title}"
+							onclick='wd.display.showComponent({show:["wdDialog"],url:"<ss:serv name='${item.play.service}' dest='${item.play.dest}' parm='${item.play.parm}'/>",title:"${item.play.title}",width:"${item.play.width}",height:"${item.play.height}",minHeight:"${item.play.minHeight}",maxHeight:"${item.play.maxHeight}"});'
 						</ss:equal>
 					>
 					<ss:equal val='${empty item.thumbnail}' val2='false'>
 						<div class="longCardList-thumbnail" style="margin-right: 18px;margin-bottom: 2px;">
 <%-- 再增加 type="img"。Lin
-							<img src="<ss@serv name='dlByHttp' parm='{"wdConfirmationCaptchaService":"0","path":"${item.thumbnail.value}"}'/>"/> --%>
-							<img src="<ss:serv name='dlByHttp' parm='{type:"img",path:"${item.thumbnail.value}",wdConfirmationCaptchaService:0}'/>"/>
+							<img src="<ss@serv name='dlByHttp' parm='{"wdConfirmationCaptchaService":"0","path":"${item.thn}"}'/>"/> --%>
+							<img src="<ss:serv name='dlByHttp' parm='{type:"img",path:"${item.thn}",wdConfirmationCaptchaService:0}'/>"/>
 						</div>
 					</ss:equal>
 					<div class="longCardList-info" style="font-size: 0px;display: inline-block;float: left;">
 						<span class="longCardList-highlight" style="margin-bottom: 3px;">
 							<a>
-								<ss:equal val='${empty item.first}' val2='false'>
+								<ss:equal val='${empty item.title}' val2='false'>
 									<%--不带codebook--%>
-									<ss:equal val='${empty item.first.field.cbName}' val2='true'>
-										<ss:txt val='${item.first.value}' fmt='${item.first.field.fmt}'/>
+									<ss:equal val='${empty item.title.cbName}' val2='true'>
+										<ss:txt val='${item.title.value}' fmt='${item.title.fmt}'/>
 									</ss:equal>
 									<%--带codebook--%>
-									<ss:equal val='${empty item.first.field.cbName}' val2='false'>
-										<ss:cbTrans cb='${item.first.field.cbName}' val='${item.first.value}'/>
+									<ss:equal val='${empty item.title.cbName}' val2='false'>
+										<ss:cbTrans cb='${item.title.cbName}' val='${item.title.value}'/>
 									</ss:equal>
 								</ss:equal>
 								<%--缺标题显示属性start--%>
-								<ss:equal val='${empty item.first && not empty item.third}' val2='true'>
-									<ss:rpt name='${item.third}' id='itemList'>
+								<ss:equal val='${empty item.title && not empty item.catList}' val2='true'>
+									<ss:rpt name='${item.catList}' id='itemList'>
 										<ss:rpt name='${itemList}' id='item2'>
 											<span>
-												${item2.field.desc}:
+												${item2.desc}:
 												<%--不带codebook--%>
-												<ss:equal val='${empty item2.field.cbName}' val2='true'>
-													<ss:txt val='${item2.value}' fmt='${item2.field.fmt}' miniDate='false'/>
+												<ss:equal val='${empty item2.cbName}' val2='true'>
+													<ss:txt val='${item2.value}' fmt='${item2.fmt}' miniDate='false'/>
 												</ss:equal>
 												<%--带codebook--%>
 												<ss:equal val='${empty item2.field.cbName}' val2='false'>
-													<ss:cbTrans cb='${item2.field.cbName}' val='${item2.value}'/>
+													<ss:cbTrans cb='${item2.cbName}' val='${item2.value}'/>
 												</ss:equal>
 											</span>
 										</ss:rpt>
@@ -60,22 +60,22 @@
 						</span>
 						<ss:equal val='${empty item.second}' val2='false'>
 							<div id="cardList-abstract${item.index}" class="longCardList-dim ${item.second.isAbstract?'growHeightDiv':'ellipsisDiv'}">
-									${item.second.value}
+									${item.abs}
 							</div>
 						</ss:equal>
-						<ss:equal val='${empty item.first && not empty item.third}' val2='false'>
-							<ss:rpt name='${item.third}' id='itemList'>
+						<ss:equal val='${empty item.title && not empty item.catList}' val2='false'>
+							<ss:rpt name='${item.catList}' id='itemList'>
 								<div id="cardList-category${item.index}-0" class="longCardList growHeightDiv">
 									<ss:rpt name='${itemList}' id='item2'>
 										<span>
-											${item2.field.desc}:
+											${item2.desc}:
 											<%--不带codebook--%>
-											<ss:equal val='${empty item2.field.cbName}' val2='true'>
-												<ss:txt val='${item2.value}' fmt='${item2.field.fmt}' miniDate='false'/>
+											<ss:equal val='${empty item2.cbName}' val2='true'>
+												<ss:txt val='${item2.value}' fmt='${item2.fmt}' miniDate='false'/>
 											</ss:equal>
 											<%--带codebook--%>
-											<ss:equal val='${empty item2.field.cbName}' val2='false'>
-												<ss:cbTrans cb='${item2.field.cbName}' val='${item2.value}'/>
+											<ss:equal val='${empty item2.cbName}' val2='false'>
+												<ss:cbTrans cb='${item2.cbName}' val='${item2.value}'/>
 											</ss:equal>
 										</span>
 									</ss:rpt>

Неке датотеке нису приказане због велике количине промена