mp_xyqj_inp.html 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  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: 8px; */
  16. box-sizing: border-box;
  17. }
  18. .table th {
  19. width: 140px;
  20. max-width: 170px;
  21. }
  22. .table td {
  23. position: relative;
  24. }
  25. .reason-input {
  26. width: 100%;
  27. }
  28. </style>
  29. </head>
  30. <body>
  31. <div id="app" v-cloak>
  32. <!-- 新增请假发起页面 by xu 2026-02-28 -->
  33. <div class="form-wrap">
  34. <table class="table">
  35. <tr>
  36. <th>请假类别</th>
  37. <td>
  38. <!-- 功能说明:下拉选项改为组件内部按 cb/url 拉取(对齐PC ss-objp),页面不再手写加载方法 by xu 2026-02-28 -->
  39. <ss-select
  40. v-model="formData.rclbm"
  41. cb="xyqjlb"
  42. :auto-select-first="true"
  43. placeholder="请选择"
  44. >
  45. </ss-select>
  46. </td>
  47. </tr>
  48. <tr>
  49. <th>学员</th>
  50. <td>
  51. <ss-select
  52. v-model="formData.fzryid"
  53. cb="xyByJzBySess"
  54. :auto-select-first="true"
  55. placeholder="请选择"
  56. @change="onStudentChange"
  57. >
  58. </ss-select>
  59. </td>
  60. </tr>
  61. <tr>
  62. <th>请假开始时间</th>
  63. <td>
  64. <ss-datetime-picker
  65. v-model="formData.kssj"
  66. mode="datetime"
  67. placeholder="YYYY-MM-DD HH:mm"
  68. @change="onStartTimeChange"
  69. >
  70. </ss-datetime-picker>
  71. </td>
  72. </tr>
  73. <tr>
  74. <th>请假结束时间</th>
  75. <td>
  76. <ss-datetime-picker
  77. v-model="formData.jssj"
  78. mode="datetime"
  79. :min-date="endMinDate"
  80. placeholder="YYYY-MM-DD HH:mm"
  81. >
  82. </ss-datetime-picker>
  83. </td>
  84. </tr>
  85. <tr>
  86. <th>事由</th>
  87. <td>
  88. <ss-input
  89. v-model="formData.ms"
  90. name="ms"
  91. class="reason-input"
  92. placeholder="请录入"
  93. />
  94. </td>
  95. </tr>
  96. </table>
  97. </div>
  98. </div>
  99. <script>
  100. window.SS.ready(function () {
  101. window.SS.dom.initializeFormApp({
  102. el: '#app',
  103. data() {
  104. return {
  105. // 初始化请假发起数据 by xu 2026-02-28
  106. pageParams: {},
  107. formData: {
  108. mc: '学员请假',
  109. fzryid: '',
  110. bjid: '',
  111. rclbm: '',
  112. kssj: '',
  113. jssj: '',
  114. ms: ''
  115. },
  116. endMinDate: '',
  117. studentLookupSeq: 0,
  118. }
  119. },
  120. watch: {
  121. // 功能说明:学员变化时自动反查班级并缓存 bjid(兼容自动选中与手动切换) by xu 2026-03-01
  122. 'formData.fzryid': function (newVal, oldVal) {
  123. const next = String(newVal || '').trim()
  124. const prev = String(oldVal || '').trim()
  125. if (next === prev) return
  126. if (!next) {
  127. this.formData.bjid = ''
  128. return
  129. }
  130. this.fetchBjidByRyid(next)
  131. }
  132. },
  133. async mounted() {
  134. this.pageParams = this.getUrlParams()
  135. this.initDefaultTimeRange()
  136. // 功能说明:向 mp_objInp 暴露统一取值方法,尽量减少表单页改动 by xu 2026-02-28
  137. window.__mpObjInpGetFormData = async () => {
  138. // 功能说明:提交前兜底反查 bjid,避免学员切换后接口未返回就提交导致缺参 by xu 2026-03-01
  139. if (this.formData.fzryid && !this.formData.bjid) {
  140. await this.fetchBjidByRyid(this.formData.fzryid)
  141. }
  142. const message = this.validateForm()
  143. return {
  144. valid: !message,
  145. message: message || '',
  146. data: {
  147. mc: this.formData.mc,
  148. fzryid: this.formData.fzryid,
  149. bjid: this.formData.bjid,
  150. rclbm: this.formData.rclbm,
  151. kssj: this.formData.kssj,
  152. jssj: this.formData.jssj,
  153. ms: (this.formData.ms || '').trim()
  154. }
  155. }
  156. }
  157. },
  158. beforeUnmount() {
  159. // 功能说明:页面卸载时清理桥接方法,避免污染其他表单页 by xu 2026-02-28
  160. try {
  161. if (window.__mpObjInpGetFormData) {
  162. delete window.__mpObjInpGetFormData
  163. }
  164. } catch (_) {}
  165. },
  166. methods: {
  167. getUrlParams() {
  168. const params = {}
  169. const urlSearchParams = new URLSearchParams(window.location.search)
  170. for (const [key, value] of urlSearchParams) {
  171. params[key] = decodeURIComponent(value)
  172. }
  173. return params
  174. },
  175. initDefaultTimeRange() {
  176. // 设置默认开始/结束时间 by xu 2026-02-28
  177. const now = new Date()
  178. const start = new Date(now.getTime() + 30 * 60 * 1000)
  179. const end = new Date(start.getTime() + 2 * 60 * 60 * 1000)
  180. this.formData.kssj = this.formatToDateTime(start)
  181. this.formData.jssj = this.formatToDateTime(end)
  182. this.endMinDate = this.formData.kssj
  183. },
  184. formatToDateTime(date) {
  185. const year = date.getFullYear()
  186. const month = String(date.getMonth() + 1).padStart(2, '0')
  187. const day = String(date.getDate()).padStart(2, '0')
  188. const hour = String(date.getHours()).padStart(2, '0')
  189. const minute = String(date.getMinutes()).padStart(2, '0')
  190. return `${year}-${month}-${day} ${hour}:${minute}`
  191. },
  192. onStartTimeChange(val) {
  193. this.endMinDate = val || ''
  194. if (this.formData.jssj && val && new Date(this.formData.jssj).getTime() < new Date(val).getTime()) {
  195. this.formData.jssj = val
  196. }
  197. },
  198. // 功能说明:手动触发学员变更时立即反查 bjid,避免等待 watch 异步节奏 by xu 2026-03-01
  199. onStudentChange(val) {
  200. const ryid = String(val || this.formData.fzryid || '').trim()
  201. if (!ryid) {
  202. this.formData.bjid = ''
  203. return
  204. }
  205. this.fetchBjidByRyid(ryid)
  206. },
  207. // 功能说明:通过 ryid 调用 xy_selBjidByXyid 反查班级并缓存到 formData.bjid by xu 2026-03-01
  208. async fetchBjidByRyid(ryid) {
  209. const value = String(ryid || '').trim()
  210. if (!value) {
  211. this.formData.bjid = ''
  212. return
  213. }
  214. const reqSeq = ++this.studentLookupSeq
  215. try {
  216. const req = (window && window.request) || request
  217. if (!req || typeof req.post !== 'function') {
  218. console.warn('[mp_xyqj_inp] request 不可用,跳过 bjid 反查')
  219. return
  220. }
  221. const response = await req.post(
  222. '/service?ssServ=xy_selBjidByXyid',
  223. { ryid: value },
  224. { loading: false, formData: true }
  225. )
  226. if (reqSeq !== this.studentLookupSeq) return
  227. const raw = response && response.data ? response.data : response
  228. const data = raw && raw.ssData !== undefined ? raw.ssData : raw
  229. // 功能说明:兼容 xy_selBjidByXyid 返回 ssData=数字/字符串/对象 三种结构 by xu 2026-03-01
  230. let bjid = ''
  231. if (data !== undefined && data !== null && (typeof data === 'number' || typeof data === 'string')) {
  232. bjid = String(data).trim()
  233. } else if (data && typeof data === 'object' && data.bjid !== undefined && data.bjid !== null) {
  234. bjid = String(data.bjid).trim()
  235. } else if (raw && typeof raw === 'object' && raw.bjid !== undefined && raw.bjid !== null) {
  236. bjid = String(raw.bjid).trim()
  237. }
  238. this.formData.bjid = bjid
  239. console.log('[mp_xyqj_inp] 学员反查班级成功', { ryid: value, bjid: this.formData.bjid })
  240. } catch (error) {
  241. if (reqSeq !== this.studentLookupSeq) return
  242. this.formData.bjid = ''
  243. console.error('[mp_xyqj_inp] 学员反查班级失败', error)
  244. }
  245. },
  246. validateForm() {
  247. if (!this.formData.rclbm) return '请选择请假类别'
  248. if (!this.formData.fzryid) return '请选择学员'
  249. if (!this.formData.kssj) return '请选择请假开始时间'
  250. if (!this.formData.jssj) return '请选择请假结束时间'
  251. // 功能说明:请假“事由/描述”改为前端非必填,仅保留其他必填项校验 by xu 2026-02-28
  252. const start = new Date(this.formData.kssj).getTime()
  253. const end = new Date(this.formData.jssj).getTime()
  254. if (!Number.isNaN(start) && !Number.isNaN(end) && end < start) {
  255. return '结束时间不能早于开始时间'
  256. }
  257. return ''
  258. }
  259. }
  260. })
  261. })
  262. </script>
  263. </body>
  264. </html>