grcz_grtfAdd.jsp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  1. <%@ page import="java.util.Map" %>
  2. <%@ page import="java.util.TreeMap" %>
  3. <%@ page language="java" pageEncoding="UTF-8" isELIgnored="false" %>
  4. <%@ taglib uri="/ssTag" prefix="ss"%>
  5. <% pageContext.setAttribute(ss.page.PageC.PAGE_objName,"grcz");%>
  6. <%pageContext.setAttribute("wdpageinformation","{'hastab':'0'}");%>
  7. <!DOCTYPE html>
  8. <html>
  9. <head>
  10. <%@ include file="/page/clip/header.jsp" %>
  11. <style>
  12. .table-container>tr>th{
  13. width:130px !important;
  14. }
  15. /* 把content-box的高度限制 从公共css 抽到具体有需要的页面 by xu 20251215 */
  16. .form-container .content-box {
  17. height: calc(100% - 80px) !important;
  18. }
  19. </style>
  20. </head>
  21. <body class="env-input-body">
  22. <form method="post" id="app" class="form-container">
  23. <div class="content-box fit-height-content">
  24. <div class="content-div" ssFith="true">
  25. <table class='form'>
  26. <tr>
  27. <th style="width: 120px">退费类别</th>
  28. <td >
  29. <script>
  30. ss.dom.formElemConfig.grczlbm={val:'11',type:window.ss.dom.TYPE.ONOFFBTN};
  31. </script>
  32. <%
  33. Map<Integer,String > grczlbMap = (Map)(request.getAttribute("grczlbMap"));
  34. for (Integer key : grczlbMap.keySet()) {
  35. pageContext.setAttribute("k",key);
  36. pageContext.setAttribute("v",grczlbMap.get(key));
  37. %>
  38. <ss-onoff
  39. v-model="grczlbm"
  40. name="grczlbm"
  41. label="${v}"
  42. value="${k}"
  43. :multiple="false"
  44. :null="false"
  45. placeholder="${v}"
  46. v-model="grczlbm"
  47. :readonly="false"
  48. onchange="handleGrczlbmChange"
  49. ></ss-onoff>
  50. <%
  51. }
  52. %>
  53. </td>
  54. </tr>
  55. <tr>
  56. <th style="width: 120px">班级/亲属</th>
  57. <td style="display: flex;align-items: center;border: none;
  58. border-right: 1px solid #e2e4ec;">
  59. <script>
  60. ss.dom.formElemConfig.bjid={val:null,type:window.ss.dom.TYPE.OBJP};
  61. </script>
  62. <ss-objp
  63. :opt="bjidOption"
  64. :inp="true"
  65. url="<ss:serv name='loadObjpOpt' parm='{"objectpickerdropdown":"1"}' />"
  66. cb="bj"
  67. v-model="bjid"
  68. name="bjid"
  69. :readonly="false"
  70. width="200px"
  71. onChange="handleBjChange"
  72. ></ss-objp>
  73. <script>
  74. ss.dom.formElemConfig.rylbm={val:'1100',type:window.ss.dom.TYPE.ONOFFBTN};
  75. </script>
  76. <ss-onoff
  77. v-model="rylbm"
  78. name="rylbm"
  79. label="职工亲属"
  80. value="1000"
  81. :multiple="true"
  82. :null="false"
  83. placeholder="职工亲属"
  84. v-model="rylbm"
  85. :readonly="false"
  86. onchange="handleRylbmChange"
  87. ></ss-onoff>
  88. </td>
  89. </tr>
  90. <%-- 先去掉,接入读卡器时再加。Lin
  91. <tr>
  92. <th>卡号</th>
  93. <td >
  94. <@input name="kah"/>
  95. </td>
  96. </tr>
  97. --%>
  98. <tr>
  99. <th>人员</th>
  100. <td>
  101. <input name="czryid" type="hidden" value='${sessionScope.ssUser.ryid}'/> <%-- 操作人员ID。Lin --%>
  102. <script>
  103. ss.dom.formElemConfig.ryid={val:null,type:window.ss.dom.TYPE.OBJP};
  104. </script>
  105. <ss-objp
  106. :opt="ryidOption"
  107. :inp="true"
  108. url="<ss:serv name='loadObjpOpt' parm='{"objectpickerdropdown":"1","objectpickerfilterField":"bjid,rylbm"}' />"
  109. cb="ryByBjOrRylb"
  110. v-model="ryid"
  111. name="ryid"
  112. :readonly="false"
  113. filterField="bjid,rylbm"
  114. onChange="selBaseInfoByRyid"
  115. ></ss-objp>
  116. </td>
  117. </tr>
  118. <tr>
  119. <th>部门/班级</th>
  120. <td id='bmbj'></td>
  121. </tr>
  122. <tr>
  123. <th>姓名</th>
  124. <td id='xm'></td>
  125. </tr>
  126. <tr>
  127. <th>人员号</th>
  128. <td id='ryh'></td>
  129. </tr>
  130. <tr>
  131. <th>金额</th>
  132. <td>
  133. <script>
  134. // 功能说明:退费金额字段改为 SsInp 组件,并声明 Vue 表单模型 by xu 20260323
  135. ss.dom.formElemConfig.je={val:'',type:window.ss.dom.TYPE.INPUT};
  136. </script>
  137. <ss-inp
  138. v-model="je"
  139. name="je"
  140. placeholder="请输入金额"
  141. ></ss-inp>
  142. </td>
  143. </tr>
  144. <tr>
  145. <th>消费余额</th>
  146. <td id='xfye'></td>
  147. </tr>
  148. <tr>
  149. <th>描述</th>
  150. <td>
  151. <script>
  152. // 功能说明:退费描述字段改为 SsInp 组件,并声明 Vue 表单模型 by xu 20260323
  153. ss.dom.formElemConfig.ms={val:'',type:window.ss.dom.TYPE.INPUT};
  154. </script>
  155. <ss-inp
  156. v-model="ms"
  157. name="ms"
  158. placeholder="请输入描述"
  159. ></ss-inp>
  160. </td>
  161. </tr>
  162. </table>
  163. </div>
  164. <input name='wdComponentID' type='hidden' value='grcz_grtfAdd'/></div>
  165. <div class='bottom-div'>
  166. <ss-bottom-button
  167. id="saveAndCommit"
  168. text="保存并提交"
  169. onclick='submitGrtfForm();'<%-- 功能说明:个人退费页提交前先校验“个人退费”金额必须为负数 by xu 20260323 --%>
  170. icon-class="bottom-div-save"
  171. ></ss-bottom-button>
  172. <ss-bottom-button
  173. text="关闭"
  174. onclick='ss.display.closeDialog();'
  175. icon-class="bottom-div-close"
  176. ></ss-bottom-button>
  177. </div>
  178. </form>
  179. <script type="text/javascript">var wdRecordValue='${wdRecordValue}';</script>
  180. <script type="text/javascript" src="/ss/js/wdRecord.js"></script>
  181. <script type="text/javascript">(function(){wdRecord("grcz_grtfAdd");})();</script>
  182. <script type="text/javascript" src="/ss/js/wdFitHeight.js"></script>
  183. <script type="text/javascript">initWdFitHeight(0)</script>
  184. <script type="text/javascript">initWdFitHeightFunction=function(){initWdFitHeight(0);};</script>
  185. <ss:equal val="${empty resizeComponent}" val2="false">
  186. <script>{var iframe=wd.display.getFrameOfWindow();
  187. if(iframe&&iframe.contentWindow==window)
  188. wd.display.resizeComponent(${resizeComponent.width}, ${resizeComponent.height}, ${empty resizeComponent.minHeight?'null':resizeComponent.minHeight}, ${empty resizeComponent.maxHeight?'null':resizeComponent.maxHeight});}</script>
  189. </ss:equal>
  190. <ss:help/>
  191. </body>
  192. <script type="text/javascript">
  193. try{wd.display.showMsgPopup('${msg}');
  194. }catch(err){console.error(err);}
  195. </script>
  196. <ss:equal val="${empty wdclosewindowparam}" val2="false">
  197. <script type="text/javascript">
  198. try{wd.display.setCloseWindowParam('${wdclosewindowparam}');
  199. }catch(err){console.error(err);}
  200. </script>
  201. </ss:equal>
  202. <script type="text/javascript" src="/js/validate/validator-rules.js"></script><%-- 功能说明:个人退费页接入桌面端校验规则,支持 SsInp 红线提示 by xu 20260323 --%>
  203. <script type="text/javascript" src="/js/validate/validation-manager.js"></script><%-- 功能说明:个人退费页接入桌面端校验管理器,支持 SsInp 红线提示 by xu 20260323 --%>
  204. </html>
  205. <%@ include file="/page/clip/footer.jsp" %>
  206. <script>
  207. // 功能说明:根据当前退费类别渲染 code-label 映射,供金额负数校验复用 by xu 20260323
  208. var GRTF_LABEL_MAP = {
  209. <%
  210. for (Integer key : grczlbMap.keySet()) {
  211. %>
  212. "<%=key%>": "<%=grczlbMap.get(key)%>",
  213. <%
  214. }
  215. %>
  216. };
  217. // 功能说明:维护个人退费页中需要强制输入负数的退费类别名称,避免依赖固定编码 by xu 20260323
  218. var NEGATIVE_ONLY_GRTF_LABEL_MAP = {
  219. "个人退费": true
  220. };
  221. // 功能说明:记录当前退费类别的最新 value/label,避免 onoff 隐藏值切换时机导致金额校验判断失真 by xu 20260323
  222. var CURRENT_GRTF_CATEGORY_STATE = {
  223. value: "",
  224. label: ""
  225. };
  226. function getFormAppVm(){
  227. var appEl = document.getElementById("app");
  228. if (!appEl || !appEl.__vue_app__ || !appEl.__vue_app__._instance) {
  229. return null;
  230. }
  231. return appEl.__vue_app__._instance.proxy || null;
  232. }
  233. function normalizeRylbmValues(value){
  234. if (Array.isArray(value)) {
  235. return value.map(function(item){
  236. return item == null ? "" : item.toString();
  237. }).filter(Boolean);
  238. }
  239. if (value == null || value === "") {
  240. return [];
  241. }
  242. var cleanValue = value.toString().replace(/^,+/, "");
  243. if (!cleanValue) {
  244. return [];
  245. }
  246. return cleanValue.split(/[,|]/).filter(Boolean);
  247. }
  248. function hasRelativeRylbmValue(value){
  249. return normalizeRylbmValues(value).indexOf("1000") !== -1;
  250. }
  251. function clearRyDisplay(){
  252. var bmbjEl = document.getElementById('bmbj');
  253. var xmEl = document.getElementById('xm');
  254. var ryhEl = document.getElementById('ryh');
  255. if (bmbjEl) bmbjEl.innerHTML = "";
  256. if (xmEl) xmEl.innerHTML = "";
  257. if (ryhEl) ryhEl.innerHTML = "";
  258. }
  259. function clearRySelection(vm){
  260. if (!vm) {
  261. clearRyDisplay();
  262. return;
  263. }
  264. vm.ryid = "";
  265. clearRyDisplay();
  266. }
  267. function handleRylbmChange(groupValue){
  268. if (!hasRelativeRylbmValue(groupValue)) {
  269. return;
  270. }
  271. var vm = getFormAppVm();
  272. if (!vm) {
  273. clearRyDisplay();
  274. return;
  275. }
  276. vm.bjid = "";
  277. clearRySelection(vm);
  278. }
  279. // 功能说明:退费类别变化后延后一拍重跑金额校验,确保隐藏字段值更新后再清理红线状态 by xu 20260323
  280. function handleGrczlbmChange(groupValue, value, label){
  281. CURRENT_GRTF_CATEGORY_STATE.value = groupValue == null ? "" : groupValue.toString();
  282. CURRENT_GRTF_CATEGORY_STATE.label = label == null ? "" : label.toString();
  283. setTimeout(function(){
  284. if (window.ssVm && typeof window.ssVm.validateField === "function") {
  285. window.ssVm.validateField("je");
  286. return;
  287. }
  288. validateNegativeAmountByCategory(false);
  289. }, 0);
  290. }
  291. // 功能说明:初始化个人退费页金额负数校验规则,整页金额都必须输入负数 by xu 20260323
  292. function initNegativeAmountValidation(){
  293. if (!window.ssVm || typeof window.ssVm.add !== "function" || window.ss.dom._grczGrtfNegativeAmountValidationInited) {
  294. return;
  295. }
  296. window.ss.dom._grczGrtfNegativeAmountValidationInited = true;
  297. window.ssVm.add("ss.commonValidator.custom", ["je"], {
  298. msgPrfx: "金额",
  299. relField: "grczlbm",
  300. validate: function(value, categoryValue){
  301. var currentLabel = getCurrentGrczlbmLabel(categoryValue);
  302. if (value == null || value.toString().trim() === "") {
  303. return true;
  304. }
  305. if (isValidNegativeAmountText(value)) {
  306. return true;
  307. }
  308. return {
  309. valid: false,
  310. message: (currentLabel || "退费") + "金额只能输入负数"
  311. };
  312. }
  313. }, {
  314. je: window.ss.dom.formElemConfig.je ? window.ss.dom.formElemConfig.je.val : ""
  315. });
  316. }
  317. // 功能说明:根据当前退费类别值读取显示文案,供联动校验和错误提示复用 by xu 20260323
  318. function getCurrentGrczlbmLabel(categoryValue){
  319. var currentValue = categoryValue == null ? getCurrentGrczlbmValue() : categoryValue.toString();
  320. if (CURRENT_GRTF_CATEGORY_STATE.label && (!currentValue || CURRENT_GRTF_CATEGORY_STATE.value === currentValue)) {
  321. return CURRENT_GRTF_CATEGORY_STATE.label;
  322. }
  323. return GRTF_LABEL_MAP[currentValue] || "";
  324. }
  325. // 功能说明:统一判断金额文本是否为合法负数,供提交校验和 ssVm 规则复用 by xu 20260323
  326. function isValidNegativeAmountText(value){
  327. var amountText = value == null ? "" : value.toString().trim();
  328. if (!amountText) {
  329. return false;
  330. }
  331. var amountNumber = Number(amountText);
  332. return !isNaN(amountNumber) && amountNumber < 0;
  333. }
  334. // 功能说明:根据当前退费类别值读取隐藏字段值,供金额校验复用 by xu 20260323
  335. function getCurrentGrczlbmValue(){
  336. var vm = getFormAppVm();
  337. if (vm && vm.grczlbm != null && vm.grczlbm !== "") {
  338. return vm.grczlbm.toString();
  339. }
  340. var categoryElem = document.querySelector('[name="grczlbm"]');
  341. return categoryElem && categoryElem.value != null ? categoryElem.value.toString() : "";
  342. }
  343. // 功能说明:统一校验个人退费金额必须为负数,不再区分具体退费类别 by xu 20260323
  344. function validateNegativeAmountByCategory(showMsg){
  345. var currentLabel = getCurrentGrczlbmLabel();
  346. var jeElem = document.querySelector('[name="je"]');
  347. if (!jeElem) {
  348. return true;
  349. }
  350. if (isValidNegativeAmountText(jeElem.value)) {
  351. return true;
  352. }
  353. if (showMsg !== false) {
  354. alert((currentLabel || "退费") + "金额只能输入负数");
  355. jeElem.focus();
  356. }
  357. return false;
  358. }
  359. // 功能说明:个人退费页提交前先走 ssVm 全量校验,确保显示 SsInp 左侧红线与底部提示 by xu 20260323
  360. function submitGrtfForm(){
  361. if (window.ssVm && window.ssVm.validations && window.ssVm.validations.size > 0) {
  362. var validateResult = window.ssVm.validateAll();
  363. if (!validateResult.valid) {
  364. return false;
  365. }
  366. } else if (!validateNegativeAmountByCategory(true)) {
  367. return false;
  368. }
  369. var formElem = document.querySelector("form");
  370. if (!formElem) {
  371. alert("表单不存在");
  372. return false;
  373. }
  374. formElem.action = "<ss:serv name='grcz_lr_tj' dest='addSure' parm='{thisViewObject:\"grcz\",dataType:\"update\"}'/>";
  375. ss.display.resizeComponent(881,361,515,515);
  376. formElem.submit();
  377. return true;
  378. }
  379. SS.ready(function(){
  380. // 功能说明:页面初始化后同步当前退费类别状态,避免首次校验读取不到最新类别文案 by xu 20260323
  381. CURRENT_GRTF_CATEGORY_STATE.value = getCurrentGrczlbmValue();
  382. CURRENT_GRTF_CATEGORY_STATE.label = GRTF_LABEL_MAP[CURRENT_GRTF_CATEGORY_STATE.value] || "";
  383. // 功能说明:页面初始化后注册个人退费金额负数校验规则,保证 SsInp 输入时直接出现红线提示 by xu 20260323
  384. initNegativeAmountValidation();
  385. });
  386. function handleBjChange(value){
  387. if (value == null || value === "") {
  388. return;
  389. }
  390. var vm = getFormAppVm();
  391. if (!vm) {
  392. clearRyDisplay();
  393. return;
  394. }
  395. if (hasRelativeRylbmValue(vm.rylbm)) {
  396. vm.rylbm = "1100";
  397. }
  398. clearRySelection(vm);
  399. }
  400. function selBaseInfoByRyid(value){
  401. $.ajax({
  402. url:"<ss:serv name='ry_selBaseInfoByRyid'/>",
  403. type:"post",
  404. data:{
  405. ryid:value
  406. },
  407. dataType:"json",
  408. success:function(data){
  409. if (data.ssCode != 0) {
  410. alert(data.ssMsg);
  411. return;
  412. }
  413. var d = data.ssData;
  414. document.getElementById('xm').innerHTML = d.xm;
  415. document.getElementById('ryh').innerHTML = d.ryh;
  416. if (d.rylbm != 1100) { // 不是学员。Lin
  417. if (d.bmmc)
  418. document.getElementById('bmbj').innerHTML = d.bmmc;
  419. else
  420. document.getElementById('bmbj').innerHTML = "(无)";
  421. } else {
  422. if (d.bjmc)
  423. document.getElementById('bmbj').innerHTML = d.bjmc;
  424. else
  425. document.getElementById('bmbj').innerHTML = "(无)";
  426. }
  427. }
  428. });
  429. }
  430. </script>