hrOvertimeDetail.vue 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. <template>
  2. <main class="cm-detail-host" v-loading="loading">
  3. <div v-if="hasData" class="cm-create-page cm-detail-page">
  4. <div class="cm-create-employee-card cm-detail-employee">
  5. <span class="cm-employee-avatar">{{ avatarText }}</span>
  6. <div class="cm-employee-info">
  7. <b
  8. >申请人:{{ applicantName || '-'
  9. }}<span class="cm-employee-no"
  10. >所属组织:{{ organizationName }}</span
  11. ><span v-if="ess.applicationNo" class="cm-employee-no"
  12. >申请编号:{{ ess.applicationNo }}</span
  13. ></b
  14. >
  15. </div>
  16. </div>
  17. <div class="cm-create-section">
  18. <div class="cm-create-section-title">加班申请信息</div>
  19. <div class="cm-create-grid">
  20. <div class="cm-compare-item">
  21. <span class="cm-compare-label">加班类型:</span
  22. ><span class="cm-compare-value">{{ overtimeTypeLabel }}</span>
  23. </div>
  24. <div class="cm-compare-item">
  25. <span class="cm-compare-label">加班时长:</span
  26. ><span class="cm-compare-value">{{ durationLabel }}</span>
  27. </div>
  28. <div class="cm-compare-item">
  29. <span class="cm-compare-label">开始日期:</span
  30. ><span class="cm-compare-value">{{ datePart(form.startTime) }}</span>
  31. </div>
  32. <div class="cm-compare-item">
  33. <span class="cm-compare-label">开始时间:</span
  34. ><span class="cm-compare-value">{{ timePart(form.startTime) }}</span>
  35. </div>
  36. <div class="cm-compare-item">
  37. <span class="cm-compare-label">结束日期:</span
  38. ><span class="cm-compare-value">{{ datePart(form.endTime) }}</span>
  39. </div>
  40. <div class="cm-compare-item">
  41. <span class="cm-compare-label">结束时间:</span
  42. ><span class="cm-compare-value">{{ timePart(form.endTime) }}</span>
  43. </div>
  44. <div class="cm-compare-item">
  45. <span class="cm-compare-label">附件:</span
  46. ><span class="cm-compare-value">
  47. <fileMain
  48. v-if="attachmentIds.length"
  49. :value="attachmentIds"
  50. type="view"
  51. size="small"
  52. />
  53. <span v-else class="cm-detail-muted">暂无附件</span>
  54. </span>
  55. </div>
  56. </div>
  57. <div v-if="form.reason" class="cm-detail-remark">
  58. <strong>申请事由:</strong>{{ form.reason }}
  59. </div>
  60. </div>
  61. </div>
  62. <el-empty v-else-if="!loading" description="暂无加班申请详情" />
  63. </main>
  64. </template>
  65. <script>
  66. import { loadAttendanceApprovalDetail } from '@/api/hr/attendanceApply';
  67. import { parseAttachmentIds } from '@/utils/attachment';
  68. /** 加班类型枚举(与 /hr/attendance/applications 的 overtimeType 口径一致) */
  69. const OVERTIME_TYPE_LABELS = {
  70. WORKDAY: '工作日加班',
  71. RESTDAY: '休息日加班',
  72. LEGAL_HOLIDAY: '法定节假日加班'
  73. };
  74. function datePart(val) {
  75. const text = String(val || '');
  76. if (!text) return '-';
  77. return text.split('T')[0].split(' ')[0];
  78. }
  79. function timePart(val) {
  80. const text = String(val || '');
  81. if (!text) return '-';
  82. const time = text.split('T')[1] || text.split(' ')[1] || '';
  83. return time ? time.slice(0, 5) : '-';
  84. }
  85. export default {
  86. name: 'HrOvertimeDetail',
  87. props: {
  88. // 待办传入的 M09 员工自助申请索引主键
  89. businessId: {
  90. default: ''
  91. },
  92. // 流程实例主键,ESS 明细缺失时回退流程表单变量
  93. id: {
  94. default: ''
  95. },
  96. deptName: {
  97. default: ''
  98. }
  99. },
  100. data() {
  101. return {
  102. loading: false,
  103. ess: {},
  104. form: {}
  105. };
  106. },
  107. computed: {
  108. hasData() {
  109. return Object.keys(this.form).length > 0;
  110. },
  111. applicantName() {
  112. return (
  113. this.ess.applicantName ||
  114. this.form.userName ||
  115. this.form.applicantName ||
  116. ''
  117. );
  118. },
  119. organizationName() {
  120. return (
  121. this.ess.organizationName ||
  122. this.form.deptName ||
  123. this.form.departmentName ||
  124. this.deptName ||
  125. '-'
  126. );
  127. },
  128. avatarText() {
  129. return this.applicantName ? this.applicantName.slice(0, 1) : '?';
  130. },
  131. overtimeTypeLabel() {
  132. const code = this.form.overtimeType;
  133. if (!code) return '-';
  134. return OVERTIME_TYPE_LABELS[code] || code;
  135. },
  136. durationLabel() {
  137. const minutes = Number(this.form.durationMinutes);
  138. if (!minutes || isNaN(minutes) || minutes <= 0) return '-';
  139. const hours = Math.floor(minutes / 60);
  140. const mins = minutes % 60;
  141. if (!hours) return `${mins} 分钟`;
  142. if (!mins) return `${hours} 小时`;
  143. return `${hours} 小时 ${mins} 分钟`;
  144. },
  145. attachmentIds() {
  146. return parseAttachmentIds(this.form);
  147. }
  148. },
  149. watch: {
  150. businessId: {
  151. immediate: true,
  152. handler() {
  153. this.getInfo();
  154. }
  155. },
  156. id() {
  157. if (!this.businessId) this.getInfo();
  158. }
  159. },
  160. methods: {
  161. datePart,
  162. timePart,
  163. async getInfo() {
  164. // 审批详情 = ESS 统一申请详情(申请人/组织/编号)+ 考勤申请明细,
  165. // 明细缺失时回退流程实例表单变量
  166. if (!this.businessId && !this.id) return;
  167. this.loading = true;
  168. try {
  169. const { ess, detail } = await loadAttendanceApprovalDetail(
  170. this.businessId,
  171. this.id
  172. );
  173. this.ess = ess || {};
  174. this.form = detail || {};
  175. } catch (e) {
  176. this.ess = {};
  177. this.form = {};
  178. this.$message.error(e.message || '加班申请详情加载失败');
  179. } finally {
  180. this.loading = false;
  181. }
  182. }
  183. }
  184. };
  185. </script>
  186. <style lang="scss" scoped src="@/styles/views/hrContractManagement/index.scss"></style>