DrillPlanViewActivities.vue 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. <template>
  2. <div v-if="drillData" class="drill-plan-detail">
  3. <div class="drill-activity-container">
  4. <div class="drill-container__title">
  5. <div class="drill-container--line"></div>
  6. <span>演练活动</span>
  7. </div>
  8. <div class="drill-container__content">
  9. <el-row :gutter="20">
  10. <el-col :span="8">
  11. <div class="drill-container__content--item">
  12. <span class="label">演练规模:</span>
  13. <span class="value">{{ getDrillScope(drillData.drillScope) }}</span>
  14. </div>
  15. </el-col>
  16. <el-col :span="8">
  17. <div class="drill-container__content--item">
  18. <span class="label">演练内容:</span>
  19. <span class="value">{{ drillData.drillContent }}</span>
  20. </div>
  21. </el-col>
  22. <el-col :span="8">
  23. <div class="drill-container__content--item">
  24. <span class="label">计划完成时间:</span>
  25. <span class="value">{{ drillData.dueCompleteTime }}</span>
  26. </div>
  27. </el-col>
  28. </el-row>
  29. <el-row :gutter="20">
  30. <el-col :span="8">
  31. <div class="drill-container__content--item">
  32. <div>
  33. <span class="label">责任部门:</span>
  34. <template v-for="(dept, index) in safatyJsonParse(drillData.responsibleDeptNameList)" :key="index">
  35. <span class="value">
  36. {{ dept }}
  37. <span v-if="index !== safatyJsonParse(drillData.responsibleDeptNameList).length - 1">、</span>
  38. </span>
  39. </template>
  40. </div>
  41. </div>
  42. </el-col>
  43. <el-col :span="8">
  44. <div class="drill-container__content--item" v-if="drillData.coordinateDeptNameList">
  45. <div>
  46. <span class="label">配合部门:</span>
  47. <template v-for="(dept, index) in safatyJsonParse(drillData.coordinateDeptNameList)" :key="index">
  48. <span class="value">
  49. {{ dept }}
  50. <span v-if="index !== safatyJsonParse(drillData.coordinateDeptNameList).length - 1">、</span>
  51. </span>
  52. </template>
  53. </div>
  54. </div>
  55. </el-col>
  56. <el-col :span="8">
  57. <div class="drill-container__content--item">
  58. <span class="label">关联应急预案:</span>
  59. <a v-if="emergencyPlanDetail" class="value font-primary" :href="emergencyPlanDetail.appendix">{{
  60. emergencyPlanDetail.planName
  61. }}</a>
  62. </div>
  63. </el-col>
  64. </el-row>
  65. <el-row :gutter="20">
  66. <el-col>
  67. <div class="drill-container__content--item">
  68. <span class="label">审批流程:</span>
  69. <span class="value">{{ getApprovalName(drillData.approvalTemplateId) }}</span>
  70. </div>
  71. </el-col>
  72. </el-row>
  73. </div>
  74. </div>
  75. <div class="drill-activity-container" style="margin-top: 20px">
  76. <div class="drill-container__title">
  77. <div class="drill-container--line"></div>
  78. <span>演练实施</span>
  79. </div>
  80. <div class="drill-container__content">
  81. <el-row :gutter="20">
  82. <el-col :span="8">
  83. <div class="drill-container__content--item">
  84. <span class="label">演练时间:</span>
  85. <span class="value">{{ drillData.drillTime }}</span>
  86. </div>
  87. </el-col>
  88. <el-col :span="8">
  89. <div class="drill-container__content--item">
  90. <span class="label">演练地点:</span>
  91. <span class="value">{{ drillData.drillLocation }}</span>
  92. </div>
  93. </el-col>
  94. <el-col :span="8">
  95. <div class="drill-container__content--item">
  96. <span class="label">演练负责人:</span>
  97. <span class="value">{{ drillData.personInChargeName }}</span>
  98. </div>
  99. </el-col>
  100. </el-row>
  101. <el-row :gutter="20">
  102. <el-col :span="8">
  103. <div class="drill-container__content--item" v-if="drillData.drillScript">
  104. <span class="label">演练脚本:</span>
  105. <span class="value font-primary link" @click="handlePreviewScript(drillData.drillScript)">{{
  106. JSON.parse(drillData.drillScript).fileName
  107. }}</span>
  108. </div>
  109. </el-col>
  110. <el-col :span="8">
  111. <div class="drill-container__content--item">
  112. <span class="label">签到码:</span>
  113. <el-popover placement="bottom" trigger="hover" width="224">
  114. <template #reference>
  115. <span style="cursor: pointer">查看签到码</span>
  116. </template>
  117. <QrCode :value="qrCode" :width="200" />
  118. </el-popover>
  119. </div>
  120. </el-col>
  121. </el-row>
  122. </div>
  123. </div>
  124. <div class="drill-container__title" style="margin-top: 20px">
  125. <div class="drill-container--line"></div>
  126. <span>演练参与部门</span>
  127. </div>
  128. <el-button style="margin-top: 20px" type="primary" :icon="Download" @click="downloadSignList(Number(id))">
  129. 下载签到名单
  130. </el-button>
  131. <BasicTable style="margin-top: 20px" :tableConfig="tableConfig" :tableData="drillData.planDetailList!">
  132. <template #drillScriptStatus="scope">
  133. <span>{{ scope.row.drillScriptStatus === 1 ? '未会签' : '已会签' }}</span>
  134. </template>
  135. </BasicTable>
  136. <PreviewOnline ref="previewOnlineRef" />
  137. </div>
  138. </template>
  139. <script setup lang="ts">
  140. import { onMounted, ref } from 'vue';
  141. import { ElMessage, ElPopover } from 'element-plus';
  142. import BasicTable from '@/components/BasicTable.vue';
  143. import { Download } from '@element-plus/icons-vue';
  144. import { useRoute } from 'vue-router';
  145. import { DrillPlanItemDetail } from '../types';
  146. import useTableConfig from '@/hooks/useTableConfigHook';
  147. import { getAllApproval } from '@/api/approval/approval';
  148. import {
  149. queryEmergencyDrillPlanDetail,
  150. queryEmergencyPlanDetail,
  151. getSignListFile,
  152. } from '@/api/emergency-drill/emergency-drill';
  153. import { DRILL_PLAN_ACTIVITIES_TABLE_OPTIONS, DRILL_PLAN_ACTIVITIES_TABLE_COLUMNS } from '../configs/plan/table';
  154. import { useEmergencyDrillHook } from '../hook';
  155. import QrCode from '@/components/Qrcode/src/Qrcode.vue';
  156. import PreviewOnline from '@/views/disaster/components/PreviewOnline.vue';
  157. import { FILE_TYPE_ICON } from '@/views/disaster/constant';
  158. import { downloadFile } from '@/views/disaster/utils/download';
  159. const route = useRoute();
  160. const id = route.query.id;
  161. const approvalList = ref();
  162. const emergencyPlanDetail = ref();
  163. const drillData = ref<DrillPlanItemDetail>();
  164. const qrCode = ref();
  165. const previewOnlineRef = ref<InstanceType<typeof PreviewOnline>>();
  166. const { getDrillScopeDict, getDrillScope } = useEmergencyDrillHook();
  167. const getApprovalList = async () => {
  168. approvalList.value = await getAllApproval();
  169. };
  170. async function getDrillData() {
  171. try {
  172. tableConfig.loading = true;
  173. drillData.value = await queryEmergencyDrillPlanDetail(id);
  174. // 获取应急预案名
  175. if (drillData.value.emergencyPlanId) {
  176. emergencyPlanDetail.value = await queryEmergencyPlanDetail(id);
  177. }
  178. // 获取二维码
  179. qrCode.value = 'https://cn.bing.com/?id=' + id + '&type=test';
  180. tableConfig.loading = false;
  181. } catch (e) {
  182. console.log(e);
  183. }
  184. }
  185. const { tableConfig } = useTableConfig(
  186. DRILL_PLAN_ACTIVITIES_TABLE_COLUMNS,
  187. DRILL_PLAN_ACTIVITIES_TABLE_OPTIONS,
  188. false,
  189. );
  190. onMounted(async () => {
  191. await getApprovalList();
  192. await getDrillScopeDict();
  193. getDrillData();
  194. });
  195. const getApprovalName = (id: number) => {
  196. return approvalList.value.find((item) => item.id === id)?.templateName;
  197. };
  198. const safatyJsonParse = (str: string) => {
  199. return str.slice(1, -1).split(',');
  200. };
  201. const handlePreviewScript = (str: string) => {
  202. const file = JSON.parse(str);
  203. const url = file.fileUrl;
  204. const type = file.fileType as keyof typeof FILE_TYPE_ICON;
  205. if (!url) return;
  206. previewOnlineRef.value?.open(url, type);
  207. };
  208. async function downloadSignList(id: number) {
  209. try {
  210. const res = await getSignListFile(id);
  211. if (res.size === 0) return;
  212. const blob = new Blob([res], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
  213. const url = window.URL.createObjectURL(blob);
  214. downloadFile(url, '演练签到名单.xlsx');
  215. } catch (e) {
  216. ElMessage.error('下载失败');
  217. console.log(e);
  218. }
  219. }
  220. </script>
  221. <style scoped lang="scss">
  222. @use '../style/common.scss' as *;
  223. .link {
  224. cursor: pointer;
  225. }
  226. </style>