PageTaskExecutionDetail.vue 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. <template>
  2. <div class="disaster-precaution-container">
  3. <header class="disaster-precaution-container__header">
  4. <img :src="BackIcon" alt="back" class="back-icon" @click="router.back()" />
  5. <span class="disaster-precaution-container__title">灾害预防检查任务</span>
  6. </header>
  7. <main class="disaster-precaution-container__main">
  8. <div class="disaster-precaution">
  9. <p class="title">
  10. 任务名称:<span class="content">{{ taskExecutionDetailList?.name }}</span>
  11. </p>
  12. <p class="title">
  13. 被检查自查单位:<span class="content">{{ taskExecutionDetailList?.deptName }}</span>
  14. </p>
  15. <TemplateTableMerge
  16. ref="templateTableMergeRef"
  17. :operation-type="operationType"
  18. :main-table="templateDetailList?.inspectTemplateDetailVOs || []"
  19. :opinion-data="templateDetailList?.deptOpinion || {} as ContentItem"
  20. :result-data="templateDetailList?.inspectResult || {} as ContentItem"
  21. :height="
  22. operationType === 'check' ? 'calc(50vh - 65px)' : operationType === 'view' ? 'calc(70vh - 100px)' : '50vh'
  23. "
  24. @validate-change="handleValidateChange"
  25. />
  26. <el-form style="max-width: 400px" :model="formModel" label-width="auto" v-if="operationType === 'check'">
  27. <el-form-item label="选择审批领导" prop="reviewerId" :rules="[{ required: true, message: '请选择审批领导' }]">
  28. <el-tree-select
  29. v-model="formModel.reviewerId"
  30. :data="treeData"
  31. node-key="id"
  32. :props="{
  33. label: 'label',
  34. children: 'children',
  35. disabled: (data) => !data.isUser || (data.id && disabledIds.includes(data.id)),
  36. }"
  37. placeholder="请选择审批领导"
  38. check-strictly
  39. filterable
  40. default-expand-all
  41. />
  42. </el-form-item>
  43. </el-form>
  44. </div>
  45. </main>
  46. <footer class="disaster-precaution-container__footer" v-if="operationType !== 'view'">
  47. <el-button @click="router.back()">取消</el-button>
  48. <el-button type="primary" @click="handleSubmit" :disabled="submitDisabled"> 提交 </el-button>
  49. </footer>
  50. </div>
  51. </template>
  52. <script lang="ts" setup>
  53. import { onMounted, ref, computed, reactive } from 'vue';
  54. import { ElMessage } from 'element-plus';
  55. import { useRoute, useRouter } from 'vue-router';
  56. import BackIcon from 'assets/svg/back.svg';
  57. import TemplateTableMerge from './src/components/TemplateTableMerge.vue';
  58. import { getTaskExecutionDetail, saveTaskDetail, saveTaskApproval } from '@/api/disaster-precaution';
  59. import { useUserInfoHook } from '@/views/disaster/hooks/userInfo';
  60. import type {
  61. TaskExecutionDetailResponse,
  62. TemplateDetailResponse,
  63. ContentItem,
  64. SaveTaskDetailRequest,
  65. } from '@/types/disaster-precaution';
  66. const { getUserFirstLevelTreeList, treeData, id: userId } = useUserInfoHook();
  67. // 需要禁用的用户ID列表
  68. const disabledIds = computed(() => {
  69. const ids = [userId];
  70. return ids;
  71. });
  72. interface FormModel {
  73. reviewerId: number | undefined;
  74. }
  75. type OperationType = 'view' | 'approve' | 'check';
  76. const templateTableMergeRef = ref<InstanceType<typeof TemplateTableMerge>>();
  77. const isFormValid = ref(false); // 表单验证状态
  78. const formModel = reactive<FormModel>({
  79. reviewerId: undefined,
  80. });
  81. const route = useRoute();
  82. const router = useRouter();
  83. const id = Number(route.params.id);
  84. const operationType = String(route.query.operationType) as OperationType;
  85. const taskExecutionDetailList = ref<TaskExecutionDetailResponse>();
  86. const templateDetailList = ref<TemplateDetailResponse>();
  87. const getTaskExecutionDetailList = async () => {
  88. const res = await getTaskExecutionDetail(id);
  89. taskExecutionDetailList.value = res;
  90. if (res.reviewerId) {
  91. formModel.reviewerId = res.reviewerId;
  92. }
  93. templateDetailList.value = JSON.parse(res.detail) as TemplateDetailResponse;
  94. };
  95. // 处理验证状态变化
  96. const handleValidateChange = (isValid: boolean) => {
  97. isFormValid.value = Boolean(isValid);
  98. };
  99. const submitDisabled = computed(() => {
  100. return !Boolean(formModel.reviewerId) || !isFormValid.value;
  101. });
  102. const handleSubmit = async () => {
  103. if (!templateTableMergeRef.value) return;
  104. const { mainTable, opinionData, resultData } = templateTableMergeRef.value.getTableData();
  105. const saveTaskDetailRequest: SaveTaskDetailRequest = {
  106. id,
  107. deptOpinion: opinionData,
  108. inspectResult: resultData,
  109. inspectDetails: mainTable,
  110. reviewerId: formModel.reviewerId as number,
  111. };
  112. // 执行提交逻辑
  113. if (operationType === 'check') {
  114. await saveTaskDetail(saveTaskDetailRequest);
  115. } else {
  116. await saveTaskApproval(saveTaskDetailRequest);
  117. }
  118. ElMessage.success('提交成功');
  119. router.back();
  120. };
  121. onMounted(() => {
  122. getTaskExecutionDetailList();
  123. getUserFirstLevelTreeList();
  124. });
  125. </script>
  126. <style lang="scss" scoped>
  127. @use '../style/disaster.scss' as *;
  128. .disaster-precaution-container__header {
  129. flex-direction: row !important;
  130. justify-content: flex-start !important;
  131. gap: 8cpx !important;
  132. }
  133. .title,
  134. .content {
  135. font-size: 14cpx;
  136. }
  137. .title {
  138. color: rgba($text-color, 0.85);
  139. }
  140. .content {
  141. color: rgba($text-color, 0.65);
  142. }
  143. </style>