mp_bjdmKqjl_baseInfo.html 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta
  6. name="viewport"
  7. content="width=device-width, initial-scale=1.0, user-scalable=no"
  8. />
  9. <title>基本信息</title>
  10. <script src="/js/mp_base/base.js"></script>
  11. <style>
  12. [v-cloak] {
  13. display: none !important;
  14. }
  15. #app {
  16. background: #f5f5f5;
  17. min-height: 100vh;
  18. padding-top: 8px;
  19. box-sizing: border-box;
  20. }
  21. /* 新增班级点名考勤记录页纯转圈加载态 by xu 2026-03-06 */
  22. .loading {
  23. min-height: 40vh;
  24. display: flex;
  25. align-items: center;
  26. justify-content: center;
  27. padding: 32px 16px;
  28. }
  29. .loading-spinner {
  30. width: 30px;
  31. height: 30px;
  32. border: 3px solid #e8f3ed;
  33. border-top-color: #40ac6d;
  34. border-radius: 50%;
  35. animation: page-spin 0.9s linear infinite;
  36. }
  37. @keyframes page-spin {
  38. from {
  39. transform: rotate(0deg);
  40. }
  41. to {
  42. transform: rotate(360deg);
  43. }
  44. }
  45. .error {
  46. text-align: center;
  47. padding: 50px;
  48. color: #ff4d4f;
  49. }
  50. .section-card {
  51. margin: 0 8px 10px;
  52. background: #ffffff;
  53. border-radius: 8px;
  54. overflow: hidden;
  55. }
  56. .form {
  57. width: 100%;
  58. border-collapse: collapse;
  59. }
  60. .form th {
  61. width: 140px;
  62. max-width: 170px;
  63. }
  64. .desc-text {
  65. white-space: pre-wrap;
  66. line-height: 1.6;
  67. }
  68. </style>
  69. </head>
  70. <body>
  71. <div id="app" v-cloak>
  72. <!-- 新增班级点名考勤记录页纯转圈加载态 by xu 2026-03-06 -->
  73. <div v-if="loading" class="loading">
  74. <div class="loading-spinner"></div>
  75. </div>
  76. <div v-else-if="error" class="error">{{ error }}</div>
  77. <!-- 新增班级点名考勤记录基本信息回显页 by xu 2026-03-06 -->
  78. <div v-else class="content-div">
  79. <div class="section-card">
  80. <table class="form">
  81. <tr>
  82. <th>名称</th>
  83. <td>{{ displayData.mc || formData.mc || '-' }}</td>
  84. </tr>
  85. <tr>
  86. <th>人员</th>
  87. <td>{{ displayData.rymc || formData.ryid || '-' }}</td>
  88. </tr>
  89. <tr>
  90. <th>开始时间</th>
  91. <td>{{ displayData.kssj || '-' }}</td>
  92. </tr>
  93. <tr>
  94. <th>结束时间</th>
  95. <td>{{ displayData.jssj || '-' }}</td>
  96. </tr>
  97. <tr>
  98. <th>考勤类别</th>
  99. <td>{{ displayData.kqlb || formData.kqlbm || '-' }}</td>
  100. </tr>
  101. <tr>
  102. <th>班级</th>
  103. <td>{{ displayData.bjmc || formData.bjid || '-' }}</td>
  104. </tr>
  105. <tr>
  106. <th>描述</th>
  107. <td class="desc-text">{{ displayData.mswj || formData.mswj || formData.ms || '-' }}</td>
  108. </tr>
  109. </table>
  110. </div>
  111. </div>
  112. </div>
  113. <script>
  114. window.SS.ready(function () {
  115. window.SS.dom.initializeFormApp({
  116. el: "#app",
  117. data() {
  118. return {
  119. pageParams: {},
  120. loading: false,
  121. error: "",
  122. formData: {},
  123. displayData: {
  124. mc: "",
  125. rymc: "",
  126. kssj: "",
  127. jssj: "",
  128. kqlb: "",
  129. bjmc: "",
  130. mswj: "",
  131. },
  132. };
  133. },
  134. async mounted() {
  135. this.pageParams = this.getUrlParams();
  136. await this.loadData();
  137. },
  138. methods: {
  139. getUrlParams() {
  140. const params = {};
  141. const urlSearchParams = new URLSearchParams(
  142. window.location.search
  143. );
  144. for (const [key, value] of urlSearchParams) {
  145. params[key] = decodeURIComponent(value);
  146. }
  147. return params;
  148. },
  149. parseParamObject(paramStr) {
  150. if (!paramStr) return {};
  151. try {
  152. return JSON.parse(paramStr);
  153. } catch (err) {
  154. try {
  155. const fixed = paramStr.replace(
  156. /([,{]\s*)([a-zA-Z_][a-zA-Z0-9_]*)\s*:/g,
  157. '$1"$2":'
  158. );
  159. return JSON.parse(fixed);
  160. } catch (err2) {
  161. console.error("解析param失败:", err2);
  162. return {};
  163. }
  164. }
  165. },
  166. async loadData() {
  167. // 加载班级点名考勤记录详情数据并回显 by xu 2026-03-06
  168. const service = this.pageParams.service;
  169. if (!service) {
  170. this.error = "缺少service参数";
  171. return;
  172. }
  173. this.loading = true;
  174. this.error = "";
  175. try {
  176. const paramObj = this.parseParamObject(this.pageParams.param);
  177. const requestData = {
  178. ...paramObj,
  179. };
  180. const appendIfMissing = (targetKey, sourceKeys) => {
  181. if (
  182. requestData[targetKey] !== undefined &&
  183. requestData[targetKey] !== null &&
  184. requestData[targetKey] !== ""
  185. ) {
  186. return;
  187. }
  188. for (let i = 0; i < sourceKeys.length; i += 1) {
  189. const sourceKey = sourceKeys[i];
  190. const value = this.pageParams[sourceKey];
  191. if (value !== undefined && value !== null && value !== "") {
  192. requestData[targetKey] = value;
  193. return;
  194. }
  195. }
  196. };
  197. appendIfMissing("sqid", ["sqid"]);
  198. appendIfMissing("shid", ["shid"]);
  199. appendIfMissing("ssObjName", ["ssObjName", "ssobjname"]);
  200. appendIfMissing("ssObjId", ["ssObjId", "ssobjid"]);
  201. appendIfMissing("bdlbm", ["bdlbm"]);
  202. appendIfMissing("dataType", ["dataType", "datatype"]);
  203. appendIfMissing("encode_shid", ["encode_shid"]);
  204. appendIfMissing("jdmc", ["jdmc"]);
  205. appendIfMissing("ssToken", ["ssToken"]);
  206. const response = await request.post(
  207. `/service?ssServ=${service}&ssDest=data`,
  208. requestData,
  209. { loading: false, formData: true }
  210. );
  211. const raw = this.pickKqjlData(response?.data);
  212. if (!raw) {
  213. this.error = "未获取到考勤记录数据";
  214. return;
  215. }
  216. this.formData = raw;
  217. await this.buildDisplayData(raw);
  218. } catch (error) {
  219. console.error("加载班级点名考勤记录基本信息失败:", error);
  220. this.error = "加载失败:" + (error.message || "未知错误");
  221. } finally {
  222. this.loading = false;
  223. }
  224. },
  225. pickKqjlData(data) {
  226. if (!data) return null;
  227. if (data.bjdmKqjl) return data.bjdmKqjl;
  228. if (data.kqjl) return data.kqjl;
  229. if (data.bjdmkqjl) return data.bjdmkqjl;
  230. if (Array.isArray(data.objectList) && data.objectList.length > 0) {
  231. return (
  232. data.objectList[0]?.bjdmKqjl ||
  233. data.objectList[0]?.kqjl ||
  234. data.objectList[0]
  235. );
  236. }
  237. if (Array.isArray(data.data) && data.data.length > 0) {
  238. return data.data[0]?.bjdmKqjl || data.data[0]?.kqjl || data.data[0];
  239. }
  240. if (typeof data === "object") return data;
  241. return null;
  242. },
  243. async buildDisplayData(raw) {
  244. // 格式化班级点名考勤记录显示字段 by xu 2026-03-06
  245. this.displayData = {
  246. mc: raw.mc || raw.name || "",
  247. rymc: await this.translateDict(
  248. "ry",
  249. raw.ryid,
  250. raw.rymc || raw.xm || raw.name
  251. ),
  252. kssj: this.formatDate(raw.kssj),
  253. jssj: this.formatDate(raw.jssj),
  254. kqlb: await this.translateKqlb(raw.kqlbm, raw.kqlb),
  255. bjmc: await this.translateDict(
  256. "bj",
  257. raw.bjid,
  258. raw.bjmc || raw.bjname
  259. ),
  260. mswj: this.normalizeDesc(raw.mswj || raw.ms || raw.sqms || ""),
  261. };
  262. },
  263. formatDate(value) {
  264. if (!value) return "";
  265. if (
  266. window.H5FieldFormatter &&
  267. typeof window.H5FieldFormatter.formatDate === "function"
  268. ) {
  269. return window.H5FieldFormatter.formatDate(
  270. value,
  271. "YYYY-MM-DD HH:mm:ss"
  272. );
  273. }
  274. return value;
  275. },
  276. normalizeDesc(value) {
  277. if (!value) return "";
  278. return String(value)
  279. .replace(/<br\s*\/?\>/gi, "\n")
  280. .replace(/<[^>]+>/g, "")
  281. .trim();
  282. },
  283. async translateDict(dictName, value, fallbackName) {
  284. if (fallbackName) return fallbackName;
  285. if (value === undefined || value === null || value === "") {
  286. return "";
  287. }
  288. try {
  289. if (typeof window.getDictOptions === "function") {
  290. const options = await window.getDictOptions(dictName);
  291. const target = (options || []).find(
  292. (item) => String(item.v) === String(value)
  293. );
  294. if (target && target.n) return target.n;
  295. }
  296. } catch (error) {
  297. console.error(`${dictName} 字典翻译失败:`, error);
  298. }
  299. return String(value);
  300. },
  301. async translateKqlb(kqlbm, fallbackName) {
  302. if (fallbackName) return fallbackName;
  303. if (kqlbm === undefined || kqlbm === null || kqlbm === "") {
  304. return "";
  305. }
  306. const code = String(kqlbm);
  307. const localMap = {
  308. 81: "出勤",
  309. 1: "缺勤",
  310. 41: "病假",
  311. 31: "事假",
  312. };
  313. try {
  314. if (typeof window.getDictOptions === "function") {
  315. const dictNames = ["kqlb", "kqlbm", "kqzt"];
  316. for (let i = 0; i < dictNames.length; i += 1) {
  317. const options = await window.getDictOptions(dictNames[i]);
  318. const target = (options || []).find(
  319. (item) => String(item.v) === code
  320. );
  321. if (target && target.n) return target.n;
  322. }
  323. }
  324. } catch (error) {
  325. console.error("考勤类别翻译失败:", error);
  326. }
  327. return localMap[code] || code;
  328. },
  329. },
  330. });
  331. });
  332. </script>
  333. </body>
  334. </html>