disasterAssessment.vue 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. <template>
  2. <Dialog custom-show type="lg" title="灾害评估" hide-footer @close="closeDialog">
  3. <!-- 表格组件 -->
  4. <div class="common-table">
  5. <div class="table-header">
  6. <div class="td">行政区划</div>
  7. <div class="td">受灾人数(人)</div>
  8. <div class="td">失踪人数(人)</div>
  9. <div class="td">死亡人数(人)</div>
  10. <div class="td">紧急转移(人)</div>
  11. <div class="td">直接经济损失(万元)</div>
  12. </div>
  13. <div v-for="(item, index) in fixedTableData" :key="index" class="tr">
  14. <div class="td">
  15. <div class="area_name-box">
  16. <div class="area_name-text" :title="item.area_name">{{ item.area_name }}</div>
  17. </div>
  18. </div>
  19. <div class="td">
  20. <div class="area_name-box">
  21. <el-input-number v-if="isEditing" v-model="item.injuries" class="custom-input" :min="0" />
  22. <div v-else class="area_name-text">{{ item.injuries }}</div>
  23. </div>
  24. </div>
  25. <div class="td">
  26. <div class="area_name-box">
  27. <el-input-number v-if="isEditing" v-model="item.missing" class="custom-input" :min="0" />
  28. <div v-else class="area_name-text">{{ item.missing }}</div>
  29. </div>
  30. </div>
  31. <div class="td">
  32. <div class="area_name-box">
  33. <el-input-number v-if="isEditing" v-model="item.deaths" class="custom-input" :min="0" />
  34. <div v-else class="area_name-text">{{ item.deaths }}</div>
  35. </div>
  36. </div>
  37. <div class="td">
  38. <div class="area_name-box">
  39. <el-input-number v-if="isEditing" v-model="item.transfer" class="custom-input" :min="0" />
  40. <div v-else class="area_name-text">{{ item.transfer }}</div>
  41. </div>
  42. </div>
  43. <div class="td">
  44. <div class="area_name-box">
  45. <el-input-number v-if="isEditing" v-model="item.economic_loss" class="custom-input" :min="0" />
  46. <div v-else class="area_name-text">{{ item.economic_loss }}</div>
  47. </div>
  48. </div>
  49. </div>
  50. <!-- 合计行 -->
  51. <div class="tr total-row">
  52. <div class="td">
  53. <div class="area_name-box">
  54. <div class="area_name-text">合计</div>
  55. </div>
  56. </div>
  57. <div class="td">
  58. <div class="area_name-box">
  59. <div class="area_name-text">{{ total.injuries }}</div>
  60. </div>
  61. </div>
  62. <div class="td">
  63. <div class="area_name-box">
  64. <div class="area_name-text">{{ total.missing }}</div>
  65. </div>
  66. </div>
  67. <div class="td">
  68. <div class="area_name-box">
  69. <div class="area_name-text">{{ total.deaths }}</div>
  70. </div>
  71. </div>
  72. <div class="td">
  73. <div class="area_name-box">
  74. <div class="area_name-text">{{ total.transfer }}</div>
  75. </div>
  76. </div>
  77. <div class="td">
  78. <div class="area_name-box">
  79. <div class="area_name-text">{{ total.economic_loss }}</div>
  80. </div>
  81. </div>
  82. </div>
  83. </div>
  84. <div v-if="!isEditing" class="btn-box">
  85. <div class="btn" @click="toggleEdit">
  86. <div class="text">编辑</div>
  87. </div>
  88. </div>
  89. <div v-if="isEditing" style="display: flex">
  90. <div class="btn-box">
  91. <div class="common-btn" @click="cancelEdit">
  92. <div class="text">取消</div>
  93. </div>
  94. <div class="common-btn-primary" @click="saveEdit">
  95. <div class="text">保存</div>
  96. </div>
  97. </div>
  98. </div>
  99. </Dialog>
  100. </template>
  101. <script setup lang="ts">
  102. import { computed, ref } from 'vue';
  103. import BigNumber from 'bignumber.js';
  104. import { getEventCasualties, uploadCasualties } from '@/api/duty/eventing';
  105. const { proxy } = getCurrentInstance() as ComponentInternalInstance;
  106. // 固定的行政区域列表
  107. const fixedRegions = ['茂名市', '茂南区', '电白区', '化州市', '高州市', '信宜市'];
  108. // 编辑状态
  109. const isEditing = ref(false);
  110. // 保存编辑前的原始数据
  111. const originalData = ref([]);
  112. // 原始数据
  113. const tableData = ref([]);
  114. // 固定区域的数据
  115. const fixedTableData = ref([]);
  116. // 合并固定区域和数据的函数
  117. const mergeDataWithFixedRegions = () => {
  118. fixedTableData.value = fixedRegions.map((region) => {
  119. // 查找是否有该区域的数据
  120. const foundData = tableData.value.find((item) => item.area_name === region);
  121. // 如果有数据则使用,否则使用默认值0
  122. return (
  123. foundData || {
  124. area_name: region,
  125. injuries: 0,
  126. missing: 0,
  127. deaths: 0,
  128. transfer: 0,
  129. economic_loss: 0
  130. }
  131. );
  132. });
  133. };
  134. // 计算合计值
  135. const total = computed(() => {
  136. // 初始化 BigNumber 对象
  137. const init = {
  138. injuries: new BigNumber(0),
  139. missing: new BigNumber(0),
  140. deaths: new BigNumber(0),
  141. transfer: new BigNumber(0),
  142. economic_loss: new BigNumber(0)
  143. };
  144. // 使用 reduce 累加
  145. const sums = fixedTableData.value.reduce((acc, item) => {
  146. return {
  147. injuries: acc.injuries.plus(new BigNumber(item.injuries || 0)),
  148. missing: acc.missing.plus(new BigNumber(item.missing || 0)),
  149. deaths: acc.deaths.plus(new BigNumber(item.deaths || 0)),
  150. transfer: acc.transfer.plus(new BigNumber(item.transfer || 0)),
  151. economic_loss: acc.economic_loss.plus(new BigNumber(item.economic_loss || 0))
  152. };
  153. }, init);
  154. // 返回格式化后的结果
  155. return {
  156. injuries: sums.injuries.toFormat(0),
  157. missing: sums.missing.toFormat(0),
  158. deaths: sums.deaths.toFormat(0),
  159. transfer: sums.transfer.toFormat(0),
  160. economic_loss: sums.economic_loss.toFormat(2)
  161. };
  162. });
  163. // 切换编辑状态
  164. const toggleEdit = () => {
  165. // 进入编辑时保存当前数据快照
  166. originalData.value = JSON.parse(JSON.stringify(fixedTableData.value));
  167. isEditing.value = true;
  168. };
  169. const saveEdit = () => {
  170. isEditing.value = false;
  171. // 保存数据到tableData
  172. // tableData.value = fixedTableData.value.filter(
  173. // (item) => item.injuries !== 0 || item.missing !== 0 || item.deaths !== 0 || item.transfer !== 0 || item.economic_loss !== 0
  174. // );
  175. uploadCasualties({'event_id': props.eventId, 'eventCasualties': fixedTableData.value}).then((res)=>{
  176. proxy?.$modal.msgSuccess(res.msg);
  177. })
  178. };
  179. const cancelEdit = () => {
  180. // 恢复编辑前的数据
  181. fixedTableData.value = JSON.parse(JSON.stringify(originalData.value));
  182. isEditing.value = false;
  183. };
  184. const emit = defineEmits(['update:show']);
  185. const closeDialog = () => {
  186. emit('update:show', false);
  187. };
  188. const props = defineProps<{
  189. eventId?: string;
  190. }>();
  191. onMounted(() => {
  192. // tableData.value = [
  193. // {
  194. // area_name: '',
  195. // injuries: 0,
  196. // missing: 0,
  197. // deaths: 0,
  198. // transfer: 0,
  199. // economic_loss: 0
  200. // }
  201. // ];
  202. // mergeDataWithFixedRegions();
  203. getEventCasualties({ event_id: props.eventId }).then((res) => {
  204. tableData.value = res.data;
  205. mergeDataWithFixedRegions();
  206. });
  207. });
  208. </script>
  209. <style scoped lang="scss">
  210. .common-table {
  211. .total-row {
  212. font-weight: bold;
  213. }
  214. .table-header,
  215. .tr {
  216. display: flex;
  217. height: 130px;
  218. .td {
  219. flex: 1;
  220. padding: 8px;
  221. .area_name-box {
  222. .area_name-text {
  223. white-space: nowrap;
  224. overflow: hidden;
  225. text-overflow: ellipsis;
  226. }
  227. .edit-input {
  228. width: 100%;
  229. padding: 4px;
  230. border: 1px solid #ccc;
  231. border-radius: 4px;
  232. text-align: center;
  233. }
  234. :deep(.el-input-number) {
  235. width: 60%;
  236. }
  237. }
  238. }
  239. }
  240. }
  241. .custom-input {
  242. :deep(.el-input-number__increase) {
  243. background-color: #ffffff;
  244. width: 50px;
  245. font-size: 25px;
  246. }
  247. :deep(.el-input-number__decrease) {
  248. background-color: #ffffff;
  249. width: 50px;
  250. font-size: 25px;
  251. }
  252. }
  253. .btn-box {
  254. flex: 1;
  255. //height: 421px;
  256. display: flex;
  257. justify-content: center;
  258. align-items: center;
  259. .btn {
  260. width: 361px;
  261. height: 136px;
  262. background: url('@/assets/images/emergencyCommandMap/communication/btn.png') no-repeat;
  263. display: flex;
  264. align-items: center;
  265. justify-content: center;
  266. cursor: pointer;
  267. .icon1,
  268. .icon2,
  269. .icon3 {
  270. margin-right: 20px;
  271. margin-top: 10px;
  272. }
  273. .icon1 {
  274. width: 64px;
  275. height: 67px;
  276. background: url('@/assets/images/emergencyCommandMap/communication/icon1.png') no-repeat;
  277. }
  278. .icon2 {
  279. width: 64px;
  280. height: 65px;
  281. background: url('@/assets/images/emergencyCommandMap/communication/icon2.png') no-repeat;
  282. }
  283. .icon3 {
  284. width: 64px;
  285. height: 63px;
  286. background: url('@/assets/images/emergencyCommandMap/communication/icon3.png') no-repeat;
  287. }
  288. .text {
  289. color: #fff;
  290. font-size: 38px;
  291. }
  292. }
  293. }
  294. </style>