mp_kqjl_baseInfo.html 9.8 KB

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