mp_kqjl_baseInfo.html 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  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">
  108. {{ displayData.ms || formData.ms || formData.mswj || '-' }}
  109. </td>
  110. </tr>
  111. </table>
  112. </div>
  113. </div>
  114. </div>
  115. <script>
  116. window.SS.ready(function () {
  117. window.SS.dom.initializeFormApp({
  118. el: "#app",
  119. data() {
  120. return {
  121. pageParams: {},
  122. loading: false,
  123. error: "",
  124. formData: {},
  125. displayData: {
  126. mc: "",
  127. rymc: "",
  128. kssj: "",
  129. jssj: "",
  130. kqlb: "",
  131. bjmc: "",
  132. ms: "",
  133. },
  134. };
  135. },
  136. async mounted() {
  137. this.pageParams = this.getUrlParams();
  138. await this.loadData();
  139. },
  140. methods: {
  141. getUrlParams() {
  142. const params = {};
  143. const urlSearchParams = new URLSearchParams(
  144. window.location.search
  145. );
  146. for (const [key, value] of urlSearchParams) {
  147. try {
  148. params[key] = decodeURIComponent(value);
  149. } catch (_) {
  150. params[key] = String(value);
  151. }
  152. }
  153. return params;
  154. },
  155. parseParamObject(paramStr) {
  156. if (!paramStr) return {};
  157. if (typeof paramStr === "object") return paramStr;
  158. try {
  159. return JSON.parse(paramStr);
  160. } catch (_) {
  161. try {
  162. const fixed = String(paramStr)
  163. .replace(/([{,]\s*)([A-Za-z0-9_]+)\s*:/g, '$1"$2":')
  164. .replace(/'/g, '"');
  165. return JSON.parse(fixed);
  166. } catch (error) {
  167. console.error("解析param失败:", error);
  168. return {};
  169. }
  170. }
  171. },
  172. async loadData() {
  173. // 加载考勤记录详情数据并回显 by xu 2026-03-06
  174. const service = String(
  175. this.pageParams.service || this.pageParams.ssServ || ""
  176. ).trim();
  177. if (!service) {
  178. this.error = "缺少service参数";
  179. return;
  180. }
  181. this.loading = true;
  182. this.error = "";
  183. try {
  184. const requestData = {
  185. ...this.parseParamObject(this.pageParams.param),
  186. };
  187. const appendIfMissing = (targetKey, sourceKeys) => {
  188. if (
  189. requestData[targetKey] !== undefined &&
  190. requestData[targetKey] !== null &&
  191. requestData[targetKey] !== ""
  192. ) {
  193. return;
  194. }
  195. for (let i = 0; i < sourceKeys.length; i += 1) {
  196. const value = this.pageParams[sourceKeys[i]];
  197. if (value !== undefined && value !== null && value !== "") {
  198. requestData[targetKey] = value;
  199. return;
  200. }
  201. }
  202. };
  203. appendIfMissing("sqid", ["sqid"]);
  204. appendIfMissing("shid", ["shid"]);
  205. appendIfMissing("ssObjName", ["ssObjName", "ssobjname"]);
  206. appendIfMissing("ssObjId", ["ssObjId", "ssobjid"]);
  207. appendIfMissing("bdlbm", ["bdlbm"]);
  208. appendIfMissing("dataType", ["dataType", "datatype"]);
  209. appendIfMissing("encode_shid", ["encode_shid"]);
  210. appendIfMissing("jdmc", ["jdmc"]);
  211. appendIfMissing("ssToken", ["ssToken"]);
  212. const response = await request.post(
  213. `/service?ssServ=${service}&ssDest=data`,
  214. requestData,
  215. { loading: false, formData: true }
  216. );
  217. const raw = this.pickKqjlData(
  218. response && response.data ? response.data : response
  219. );
  220. if (!raw) {
  221. this.error = "未获取到考勤记录数据";
  222. return;
  223. }
  224. this.formData = raw;
  225. await this.buildDisplayData(raw);
  226. } catch (error) {
  227. console.error("加载考勤记录基本信息失败:", error);
  228. this.error =
  229. "加载失败:" + ((error && error.message) || "未知错误");
  230. } finally {
  231. this.loading = false;
  232. }
  233. },
  234. pickKqjlData(data) {
  235. if (!data) return null;
  236. if (data.kqjl) return data.kqjl;
  237. if (data.bjdmKqjl) return data.bjdmKqjl;
  238. if (
  239. Array.isArray(data.objectList) &&
  240. data.objectList.length > 0
  241. ) {
  242. return (
  243. data.objectList[0].kqjl ||
  244. data.objectList[0].bjdmKqjl ||
  245. data.objectList[0]
  246. );
  247. }
  248. if (Array.isArray(data.data) && data.data.length > 0) {
  249. return (
  250. data.data[0].kqjl || data.data[0].bjdmKqjl || data.data[0]
  251. );
  252. }
  253. if (typeof data === "object") return data;
  254. return null;
  255. },
  256. async buildDisplayData(raw) {
  257. // 格式化考勤记录显示字段 by xu 2026-03-06
  258. this.displayData = {
  259. mc: raw.mc || "",
  260. rymc: await this.translateStudentByBj(raw),
  261. kssj: this.formatDate(raw.kssj),
  262. jssj: this.formatDate(raw.jssj),
  263. kqlb: await this.translateDict("kqlb", raw.kqlbm, raw.kqlb),
  264. bjmc: await this.translateClassName(raw),
  265. ms: this.normalizeDesc(raw.ms || raw.mswj || ""),
  266. };
  267. },
  268. formatDate(value) {
  269. if (!value) return "";
  270. if (
  271. window.H5FieldFormatter &&
  272. typeof window.H5FieldFormatter.formatDate === "function"
  273. ) {
  274. return window.H5FieldFormatter.formatDate(
  275. value,
  276. "YYYY-MM-DD HH:mm:ss"
  277. );
  278. }
  279. return value;
  280. },
  281. normalizeDesc(value) {
  282. if (!value) return "";
  283. return String(value)
  284. .replace(/<br\s*\/?\>/gi, "\n")
  285. .replace(/<[^>]+>/g, "")
  286. .trim();
  287. },
  288. async translateStudentByBj(raw) {
  289. const fallbackName = raw.rymc || raw.xm || "";
  290. if (fallbackName) return fallbackName;
  291. if (
  292. !raw ||
  293. raw.ryid === undefined ||
  294. raw.ryid === null ||
  295. raw.ryid === ""
  296. )
  297. return "";
  298. if (!raw.bjid) {
  299. return this.translateDict("ry", raw.ryid, fallbackName);
  300. }
  301. try {
  302. // 功能说明:考勤记录基本信息页按班级翻译人员名称,避免同人码本无法按班级定位 by xu 2026-03-18
  303. const response = await request.post(
  304. "/service?ssServ=loadObjpOpt&objectpickerdropdown1=1",
  305. {
  306. objectpickerparam: JSON.stringify({
  307. input: "false",
  308. codebook: "xyByBj",
  309. bjid: raw.bjid,
  310. cascadingLevel: "bjid,ryid",
  311. }),
  312. objectpickertype: 2,
  313. objectpickervalue: raw.ryid,
  314. upperValue: raw.bjid,
  315. },
  316. { loading: false, formData: true }
  317. );
  318. if (response && response.data && response.data.result) {
  319. const translated =
  320. response.data.result[String(raw.ryid)] ||
  321. response.data.result[raw.ryid];
  322. if (translated) return translated;
  323. }
  324. } catch (error) {
  325. console.error("xyByBj 人员翻译失败:", error);
  326. }
  327. return String(raw.ryid);
  328. },
  329. async translateClassName(raw) {
  330. const fallbackName = raw.bjmc || raw.bjname || "";
  331. if (fallbackName) return fallbackName;
  332. if (
  333. !raw ||
  334. raw.bjid === undefined ||
  335. raw.bjid === null ||
  336. raw.bjid === ""
  337. ) {
  338. return "";
  339. }
  340. const translated = await this.translateDict(
  341. "adminBj",
  342. raw.bjid,
  343. ""
  344. );
  345. if (translated && String(translated) !== String(raw.bjid)) {
  346. return translated;
  347. }
  348. return this.translateDict("bj", raw.bjid, fallbackName);
  349. },
  350. async translateDict(dictName, value, fallbackName) {
  351. if (fallbackName) return fallbackName;
  352. if (value === undefined || value === null || value === "")
  353. return "";
  354. try {
  355. if (typeof window.getDictOptions === "function") {
  356. const options = await window.getDictOptions(dictName);
  357. const target = (options || []).find(
  358. (item) => String(item.v) === String(value)
  359. );
  360. if (target && target.n) return target.n;
  361. }
  362. } catch (error) {
  363. console.error(`${dictName} 字典翻译失败:`, error);
  364. }
  365. return String(value);
  366. },
  367. },
  368. });
  369. });
  370. </script>
  371. </body>
  372. </html>