edit.vue 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655
  1. <template>
  2. <div class="safety-platform-container">
  3. <header class="safety-platform-container__header">
  4. <div class="breadcrumb-title"><BreadcrumbBack /> 编辑危险作业申请</div>
  5. </header>
  6. <main class="safety-platform-container__main">
  7. <el-form ref="formRef" :model="formValue" :rules="rules" label-width="160px" label-position="right">
  8. <div class="section-title">基础信息</div>
  9. <div class="form-grid">
  10. <el-form-item label="审批流程" prop="templateId" class="span-full">
  11. <el-select v-model="formValue.templateId" placeholder="请选择审批流程" size="large" clearable>
  12. <el-option v-for="opt in approvalOptions" :key="opt.id" :label="opt.templateName" :value="opt.id" />
  13. </el-select>
  14. </el-form-item>
  15. <el-form-item label="作业类型" prop="hazardOperationType">
  16. <el-select disabled size="large" v-model="formValue.hazardOperationType" class="w-100">
  17. <el-option :value="1" label="有限空间作业" />
  18. <el-option :value="2" label="高处作业" />
  19. <el-option :value="3" label="临时用电" />
  20. <el-option :value="4" label="动火作业" />
  21. </el-select>
  22. </el-form-item>
  23. <el-form-item label="申请单位" prop="applicationUnitName"
  24. ><el-input size="large" v-model="formValue.applicationUnitName"
  25. /></el-form-item>
  26. <el-form-item label="申请人" prop="applicantName"
  27. ><el-input size="large" v-model="formValue.applicantName"
  28. /></el-form-item>
  29. <el-form-item label="申请部门" prop="applicationDepartment"
  30. ><el-cascader
  31. v-model="formValue.applicationDepartmentId"
  32. size="large"
  33. ref="cascaderRef"
  34. :options="firstLevelDepts"
  35. :props="cascaderProp"
  36. :show-all-levels="false"
  37. placeholder="请选择部门名称"
  38. filterable
  39. @change="handleChangeDept"
  40. style="width: 100%"
  41. /></el-form-item>
  42. <el-form-item label="联系电话" prop="applicantPhone"
  43. ><el-input size="large" v-model="formValue.applicantPhone"
  44. /></el-form-item>
  45. <el-form-item label="备注信息" prop="remark" class="span-full">
  46. <el-input size="large" v-model="formValue.remark" type="textarea" :rows="2" placeholder="备注信息..." />
  47. </el-form-item>
  48. </div>
  49. <div class="form-line-divider"></div>
  50. <template v-if="formValue.hazardOperationType === 1">
  51. <div class="section-title">有限空间作业详情</div>
  52. <div class="form-grid">
  53. <el-form-item label="所属单位" prop="space.confinedSpaceUnit"
  54. ><el-input size="large" v-model="formValue.space.confinedSpaceUnit"
  55. /></el-form-item>
  56. <el-form-item label="空间名称" prop="space.confinedSpaceName"
  57. ><el-input size="large" v-model="formValue.space.confinedSpaceName"
  58. /></el-form-item>
  59. <el-form-item label="负责人" prop="space.unitResponsible"
  60. ><el-input size="large" v-model="formValue.space.unitResponsible"
  61. /></el-form-item>
  62. <el-form-item label="监护人" prop="space.supervisor"
  63. ><el-input size="large" v-model="formValue.space.supervisor"
  64. /></el-form-item>
  65. <el-form-item label="作业人" prop="space.operator"
  66. ><el-input size="large" v-model="formValue.space.operator" placeholder="多人请用逗号分隔"
  67. /></el-form-item>
  68. <el-form-item label="其他作业" prop="space.otherSpecialOps"
  69. ><el-input size="large" v-model="formValue.space.otherSpecialOps"
  70. /></el-form-item>
  71. <el-form-item label="开始时间" prop="space.operationStartTime"
  72. ><el-date-picker
  73. size="large"
  74. v-model="formValue.space.operationStartTime"
  75. value-format="YYYY-MM-DD"
  76. class="w-100"
  77. /></el-form-item>
  78. <el-form-item label="结束时间" prop="space.operationEndTime"
  79. ><el-date-picker
  80. size="large"
  81. v-model="formValue.space.operationEndTime"
  82. value-format="YYYY-MM-DD"
  83. class="w-100"
  84. /></el-form-item>
  85. </div>
  86. <div class="sub-group-box">
  87. <div class="sub-label is-required-manual section-title-flex">环境当前浓度指标 (初始评估)</div>
  88. <el-table :data="[formValue.space]" border class="density-table" style="margin-bottom: 20px">
  89. <el-table-column label="有毒有害物质 (toxicHazardous)">
  90. <template #default="scope">
  91. <el-form-item prop="space.toxicHazardous" :rules="r" label-width="0" class="m-0"
  92. ><el-input v-model="scope.row.toxicHazardous"
  93. /></el-form-item>
  94. </template>
  95. </el-table-column>
  96. <el-table-column label="可燃气 (flammable)">
  97. <template #default="scope">
  98. <el-form-item prop="space.flammable" :rules="r" label-width="0" class="m-0"
  99. ><el-input v-model="scope.row.flammable"
  100. /></el-form-item>
  101. </template>
  102. </el-table-column>
  103. <el-table-column label="氧含量 (oxygenContent)">
  104. <template #default="scope">
  105. <el-form-item prop="space.oxygenContent" :rules="r" label-width="0" class="m-0"
  106. ><el-input v-model="scope.row.oxygenContent"
  107. /></el-form-item>
  108. </template>
  109. </el-table-column>
  110. </el-table>
  111. </div>
  112. <div class="form-grid mt-20">
  113. <el-form-item label="作业内容" prop="space.operationContent" class="span-full"
  114. ><el-input size="large" v-model="formValue.space.operationContent" type="textarea"
  115. /></el-form-item>
  116. <el-form-item label="危害辨识" prop="space.hazardIdentification" class="span-full"
  117. ><el-input size="large" v-model="formValue.space.hazardIdentification" type="textarea"
  118. /></el-form-item>
  119. <el-form-item label="作业附件" class="span-full"
  120. ><UploadFiles
  121. label="上传附件"
  122. @upload-success="(l) => handleUpload('space', 'attachment', l)"
  123. :fileList="listMap['space.attachment']"
  124. /></el-form-item>
  125. </div>
  126. </template>
  127. <template v-else-if="formValue.hazardOperationType === 2">
  128. <div class="section-title">高处作业详情</div>
  129. <div class="form-grid">
  130. <el-form-item label="作业地点" prop="highAltitude.operationLocation"
  131. ><el-input size="large" v-model="formValue.highAltitude.operationLocation"
  132. /></el-form-item>
  133. <el-form-item label="作业单位" prop="highAltitude.operationUnit"
  134. ><el-input size="large" v-model="formValue.highAltitude.operationUnit"
  135. /></el-form-item>
  136. <el-form-item label="作业高度(m)" prop="highAltitude.operationHeight"
  137. ><el-input-number
  138. size="large"
  139. v-model="formValue.highAltitude.operationHeight"
  140. class="w-100"
  141. :controls="false"
  142. /></el-form-item>
  143. <el-form-item label="作业类别" prop="highAltitude.operationType"
  144. ><el-input size="large" v-model="formValue.highAltitude.operationType" placeholder="如:悬挂作业"
  145. /></el-form-item>
  146. <el-form-item label="作业人姓名" prop="highAltitude.operatorName"
  147. ><el-input size="large" v-model="formValue.highAltitude.operatorName"
  148. /></el-form-item>
  149. <el-form-item label="监护人" prop="highAltitude.supervisor"
  150. ><el-input size="large" v-model="formValue.highAltitude.supervisor"
  151. /></el-form-item>
  152. <el-form-item label="开始时间" prop="highAltitude.operationStartTime"
  153. ><el-date-picker
  154. size="large"
  155. v-model="formValue.highAltitude.operationStartTime"
  156. value-format="YYYY-MM-DD"
  157. class="w-100"
  158. /></el-form-item>
  159. <el-form-item label="结束时间" prop="highAltitude.operationEndTime"
  160. ><el-date-picker
  161. size="large"
  162. v-model="formValue.highAltitude.operationEndTime"
  163. value-format="YYYY-MM-DD"
  164. class="w-100"
  165. /></el-form-item>
  166. <el-form-item label="作业内容" prop="highAltitude.operationContent" class="span-full"
  167. ><el-input size="large" v-model="formValue.highAltitude.operationContent" type="textarea"
  168. /></el-form-item>
  169. <el-form-item label="危害辨识" prop="highAltitude.hazardIdentification" class="span-full"
  170. ><el-input size="large" v-model="formValue.highAltitude.hazardIdentification" type="textarea"
  171. /></el-form-item>
  172. <el-form-item label="作业附件" class="span-full"
  173. ><UploadFiles
  174. label="上传附件"
  175. @upload-success="(l) => handleUpload('highAltitude', 'attachment', l)"
  176. :fileList="listMap['highAltitude.attachment']"
  177. /></el-form-item>
  178. </div>
  179. </template>
  180. <template v-else-if="formValue.hazardOperationType === 3">
  181. <div class="section-title">临时用电详情</div>
  182. <div class="form-grid">
  183. <el-form-item label="需求部门" prop="electricityList.requestDepartment"
  184. ><el-input size="large" v-model="formValue.electricityList.requestDepartment"
  185. /></el-form-item>
  186. <el-form-item label="用电类型" prop="electricityList.electricityType">
  187. <el-select v-model="formValue.electricityList.electricityType" class="w-100">
  188. <el-option :value="1" label="长期" /><el-option :value="2" label="临时" />
  189. </el-select>
  190. </el-form-item>
  191. <el-form-item label="责任人" prop="electricityList.contactPerson"
  192. ><el-input size="large" v-model="formValue.electricityList.contactPerson"
  193. /></el-form-item>
  194. <el-form-item label="设备功率" prop="electricityList.equipmentPower"
  195. ><el-input size="large" v-model="formValue.electricityList.equipmentPower"
  196. /></el-form-item>
  197. <el-form-item label="开始时间" prop="electricityList.operationStartTime"
  198. ><el-date-picker
  199. size="large"
  200. v-model="formValue.electricityList.operationStartTime"
  201. value-format="YYYY-MM-DD"
  202. class="w-100"
  203. /></el-form-item>
  204. <el-form-item label="结束时间" prop="electricityList.operationEndTime"
  205. ><el-date-picker
  206. size="large"
  207. v-model="formValue.electricityList.operationEndTime"
  208. value-format="YYYY-MM-DD"
  209. class="w-100"
  210. /></el-form-item>
  211. <el-form-item label="保护措施" prop="electricityList.safety" class="span-full"
  212. ><el-input size="large" v-model="formValue.electricityList.safety"
  213. /></el-form-item>
  214. <el-form-item label="用电事由" prop="electricityList.reason" class="span-full"
  215. ><el-input size="large" v-model="formValue.electricityList.reason" type="textarea"
  216. /></el-form-item>
  217. <el-form-item label="申请附件" class="span-full"
  218. ><UploadFiles
  219. label="上传附件"
  220. @upload-success="(l) => handleUpload('electricityList', 'attachment', l)"
  221. :fileList="listMap['electricityList.attachment']"
  222. /></el-form-item>
  223. </div>
  224. </template>
  225. <template v-else-if="formValue.hazardOperationType === 4">
  226. <div class="section-title">动火作业详情</div>
  227. <div class="sub-label">A. 动火任务信息</div>
  228. <div class="form-grid">
  229. <el-form-item label="动火地点" prop="hot.hotWorkLocation"
  230. ><el-input size="large" v-model="formValue.hot.hotWorkLocation"
  231. /></el-form-item>
  232. <el-form-item label="动火级别" prop="hot.hotWorkLevel">
  233. <el-select v-model="formValue.hot.hotWorkLevel" class="w-100">
  234. <el-option :value="1" label="一级" /><el-option :value="2" label="二级" /><el-option
  235. :value="3"
  236. label="三级"
  237. />
  238. </el-select>
  239. </el-form-item>
  240. <el-form-item label="特殊时段" prop="hot.isSpecialPeriod">
  241. <el-radio-group v-model="formValue.hot.isSpecialPeriod">
  242. <el-radio :label="1">是 (节假日/重大活动)</el-radio>
  243. <el-radio :label="0">否</el-radio>
  244. </el-radio-group>
  245. </el-form-item>
  246. <el-form-item label="动火类型" prop="hot.hotWorkType"
  247. ><el-input size="large" v-model="formValue.hot.hotWorkType" placeholder="气焊/电焊/打磨等"
  248. /></el-form-item>
  249. <el-form-item label="开始时间" prop="hot.hotWorkStart"
  250. ><el-date-picker
  251. size="large"
  252. v-model="formValue.hot.hotWorkStart"
  253. value-format="YYYY-MM-DD"
  254. class="w-100"
  255. /></el-form-item>
  256. <el-form-item label="结束时间" prop="hot.hotWorkEnd"
  257. ><el-date-picker size="large" v-model="formValue.hot.hotWorkEnd" value-format="YYYY-MM-DD" class="w-100"
  258. /></el-form-item>
  259. <el-form-item label="动火任务" prop="hot.hotWorkTask" class="span-full"
  260. ><el-input size="large" v-model="formValue.hot.hotWorkTask" type="textarea"
  261. /></el-form-item>
  262. <el-form-item label="危险性分析" prop="hot.hazardAnalysis" class="span-full"
  263. ><el-input size="large" v-model="formValue.hot.hazardAnalysis" type="textarea"
  264. /></el-form-item>
  265. </div>
  266. <div class="sub-label">B. 责任人信息</div>
  267. <div class="form-grid">
  268. <el-form-item label="动火作业人员" prop="hot.hotWorkman"
  269. ><el-input size="large" v-model="formValue.hot.hotWorkman"
  270. /></el-form-item>
  271. <el-form-item label="动火人电话" prop="hot.hotWorkContact"
  272. ><el-input size="large" v-model="formValue.hot.hotWorkContact"
  273. /></el-form-item>
  274. <el-form-item label="施工单位监护人" prop="hot.constructionSupervisor"
  275. ><el-input size="large" v-model="formValue.hot.constructionSupervisor"
  276. /></el-form-item>
  277. <el-form-item label="监护人电话" prop="hot.supervisorContact"
  278. ><el-input size="large" v-model="formValue.hot.supervisorContact"
  279. /></el-form-item>
  280. <el-form-item label="现场负责人" prop="hot.constructionSiteLeader"
  281. ><el-input size="large" v-model="formValue.hot.constructionSiteLeader"
  282. /></el-form-item>
  283. <el-form-item label="教育人" prop="hot.constructionEducator"
  284. ><el-input size="large" v-model="formValue.hot.constructionEducator"
  285. /></el-form-item>
  286. <el-form-item label="申请部门监护人" prop="hot.hotWorkSupervisor"
  287. ><el-input size="large" v-model="formValue.hot.hotWorkSupervisor"
  288. /></el-form-item>
  289. <el-form-item label="部门监护电话" prop="hot.supervisorNumber"
  290. ><el-input size="large" v-model="formValue.hot.supervisorNumber"
  291. /></el-form-item>
  292. </div>
  293. <div class="sub-label">C. 防护措施与附件</div>
  294. <div class="form-grid">
  295. <el-form-item label="安全防护措施" prop="hot.fireSafetyMeasures" class="span-full"
  296. ><el-input size="large" v-model="formValue.hot.fireSafetyMeasures" type="textarea"
  297. /></el-form-item>
  298. <el-form-item label="现场检查情况" prop="hot.supervisorMeasures" class="span-full"
  299. ><el-input size="large" v-model="formValue.hot.supervisorMeasures" type="textarea"
  300. /></el-form-item>
  301. <el-form-item label="动火现场照片"
  302. ><UploadFiles
  303. label="上传附件"
  304. @upload-success="(l) => handleUpload('hot', 'photos', l)"
  305. :fileList="listMap['hot.photos']"
  306. /></el-form-item>
  307. <el-form-item label="身份证复印件"
  308. ><UploadFiles
  309. label="上传附件"
  310. @upload-success="(l) => handleUpload('hot', 'idCard', l)"
  311. :fileList="listMap['hot.idCard']"
  312. /></el-form-item>
  313. <el-form-item label="特种作业证"
  314. ><UploadFiles
  315. label="上传附件"
  316. @upload-success="(l) => handleUpload('hot', 'optionCard', l)"
  317. :fileList="listMap['hot.optionCard']"
  318. /></el-form-item>
  319. <el-form-item label="安全教育记录"
  320. ><UploadFiles
  321. label="上传附件"
  322. @upload-success="(l) => handleUpload('hot', 'safetyEducationPlan', l)"
  323. :fileList="listMap['hot.safetyEducationPlan']"
  324. /></el-form-item>
  325. <el-form-item label="施工方案"
  326. ><UploadFiles
  327. label="上传附件"
  328. @upload-success="(l) => handleUpload('hot', 'constructionPlan', l)"
  329. :fileList="listMap['hot.constructionPlan']"
  330. /></el-form-item>
  331. <el-form-item label="准备工作照片"
  332. ><UploadFiles
  333. label="上传附件"
  334. @upload-success="(l) => handleUpload('hot', 'preparationPhotos', l)"
  335. :fileList="listMap['hot.preparationPhotos']"
  336. /></el-form-item>
  337. <el-form-item label="管理协议"
  338. ><UploadFiles
  339. label="上传附件"
  340. @upload-success="(l) => handleUpload('hot', 'safetyManagementAgreement', l)"
  341. :fileList="listMap['hot.safetyManagementAgreement']"
  342. /></el-form-item>
  343. </div>
  344. </template>
  345. <div class="form-line-divider"></div>
  346. <div class="section-title-flex">
  347. <span class="is-required-manual">安全措施清单</span>
  348. <el-button type="primary" @click="addRow('measure')">+ 新增措施</el-button>
  349. </div>
  350. <el-table :data="formValue.measure" border class="mb-20">
  351. <el-table-column label="序号" prop="serialNumber" width="100" align="center" />
  352. <el-table-column label="措施内容"
  353. ><template #default="scope"><el-input v-model="scope.row.safetyMeasure" /></template
  354. ></el-table-column>
  355. <el-table-column label="确认人" width="200"
  356. ><template #default="scope"><el-input v-model="scope.row.confirmer" /></template
  357. ></el-table-column>
  358. <el-table-column label="操作" width="80" align="center">
  359. <template #default="scope"
  360. ><el-button type="primary" link @click="removeRow('measure', scope.$index)">删除</el-button></template
  361. >
  362. </el-table-column>
  363. </el-table>
  364. <div class="section-title-flex">
  365. <span class="is-required-manual">危害分析记录</span>
  366. <el-button type="primary" @click="addRow('analysis')">+ 新增记录</el-button>
  367. </div>
  368. <el-table :data="formValue.analysis" border>
  369. <el-table-column label="检测部位"
  370. ><template #default="scope"><el-input v-model="scope.row.analysisPosition" /></template
  371. ></el-table-column>
  372. <el-table-column label="有毒物质及浓度"
  373. ><template #default="scope"><el-input v-model="scope.row.toxicSubstance" /></template
  374. ></el-table-column>
  375. <el-table-column label="可燃气及浓度"
  376. ><template #default="scope"><el-input v-model="scope.row.flammableGas" /></template
  377. ></el-table-column>
  378. <el-table-column label="氧含量"
  379. ><template #default="scope"><el-input v-model="scope.row.oxygenContent" /></template
  380. ></el-table-column>
  381. <el-table-column label="检测人" width="130"
  382. ><template #default="scope"><el-input v-model="scope.row.analyst" /></template
  383. ></el-table-column>
  384. <el-table-column label="检测时间" width="220"
  385. ><template #default="scope">
  386. <el-date-picker
  387. v-model="scope.row.analysisTime"
  388. value-format="YYYY-MM-DD"
  389. style="width: 100%"
  390. /> </template
  391. ></el-table-column>
  392. <el-table-column label="操作" width="80" align="center">
  393. <template #default="scope"
  394. ><el-button type="primary" link @click="removeRow('analysis', scope.$index)">删除</el-button></template
  395. >
  396. </el-table-column>
  397. </el-table>
  398. </el-form>
  399. </main>
  400. <footer class="safety-platform-container__footer">
  401. <el-button size="large" @click="router.back()">取 消</el-button>
  402. <el-button type="primary" size="large" :loading="loading" @click="handleSave">提交</el-button>
  403. </footer>
  404. </div>
  405. </template>
  406. <script lang="ts" setup>
  407. import { ref, reactive, onMounted, nextTick } from 'vue';
  408. import { useRouter, useRoute } from 'vue-router';
  409. import { ElMessage } from 'element-plus';
  410. import UploadFiles from '@/components/UploadFiles/UploadFiles.vue';
  411. import { getAllApproval } from '@/api/approval/approval';
  412. import {
  413. dangerWorkQueryDetail,
  414. dangerWorkUpdateDangerWork,
  415. } from '@/api/production-safety/responsibility-implementation';
  416. import { formatDeptTree } from '@/views/disaster/utils/formatDeptTree';
  417. import { getAllDepartments } from '@/api/auth/dept';
  418. import { unformatAttachment, formatAttachmentList } from '@/components/UploadFiles/utils';
  419. const router = useRouter();
  420. const route = useRoute();
  421. const formRef = ref<any>(null);
  422. const loading = ref(false);
  423. const detailId = route.query.id as string;
  424. const approvalOptions = ref<any[]>([]);
  425. const firstLevelDepts = ref<any[]>([]);
  426. const cascaderRef = ref<any>(null);
  427. const cascaderProp = { expandTrigger: 'click', checkStrictly: true, value: 'id', label: 'deptName' };
  428. /**
  429. * 1. 附件显示映射 (仅用于组件内部回显显示)
  430. */
  431. const listMap = reactive<any>({
  432. 'space.attachment': [],
  433. 'highAltitude.attachment': [],
  434. 'electricityList.attachment': [],
  435. 'hot.photos': [],
  436. 'hot.idCard': [],
  437. 'hot.optionCard': [],
  438. 'hot.safetyEducationPlan': [],
  439. 'hot.constructionPlan': [],
  440. 'hot.preparationPhotos': [],
  441. 'hot.safetyManagementAgreement': [],
  442. });
  443. /**
  444. * 2. 初始化表单数据结构 (保持深度对象存在)
  445. */
  446. const formValue = reactive<any>({
  447. id: detailId,
  448. templateId: '',
  449. applicationDepartment: '',
  450. applicationDepartmentId: [],
  451. applicationUnitName: '',
  452. applicantName: '',
  453. applicantPhone: '',
  454. hazardOperationType: '',
  455. remark: '',
  456. // 必须预设这些对象,防止赋值时路径不存在
  457. space: { attachment: '' },
  458. highAltitude: { attachment: '' },
  459. electricityList: { attachment: '' },
  460. hot: {
  461. photos: '',
  462. idCard: '',
  463. optionCard: '',
  464. safetyEducationPlan: '',
  465. constructionPlan: '',
  466. preparationPhotos: '',
  467. safetyManagementAgreement: '',
  468. },
  469. measure: [],
  470. analysis: [],
  471. });
  472. const r = { required: true, message: '此项必填', trigger: ['blur', 'change'] };
  473. const rules = reactive({
  474. templateId: [r],
  475. applicationUnitName: [r],
  476. applicantName: [r],
  477. applicationDepartmentId: [r],
  478. applicantPhone: [r],
  479. });
  480. /**
  481. * 3. 关键:上传成功回调
  482. * @param obj 对应的对象名 (如 'space')
  483. * @param key 对应的字段名 (如 'attachment')
  484. * @param list 组件返回的最新的 fileList 数组
  485. */
  486. const handleUpload = async (obj: string, key: string, list: any[]) => {
  487. listMap[`${obj}.${key}`] = list;
  488. if (formValue[obj]) {
  489. const formatted = await formatAttachmentList(list);
  490. formValue[obj][key] = formatted.length > 0 ? JSON.stringify(formatted) : '';
  491. }
  492. };
  493. /**
  494. * 4. 详情回显
  495. */
  496. const getDetail = async () => {
  497. if (!detailId) return;
  498. try {
  499. const res = await dangerWorkQueryDetail(detailId);
  500. // 1. 基础属性拷贝
  501. Object.assign(formValue, res);
  502. // 2. 等待 DOM 和 v-if 完成渲染 (确保 Upload 控件已经挂载)
  503. await nextTick();
  504. const typeKeyMap: any = { 1: 'space', 2: 'highAltitude', 3: 'electricityList', 4: 'hot' };
  505. const activeObjName = typeKeyMap[formValue.hazardOperationType];
  506. if (!activeObjName) return;
  507. // 3. 附件处理逻辑
  508. Object.keys(listMap).forEach((path) => {
  509. // 检查当前路径是否属于选中的作业类型 (例如 "space.attachment")
  510. if (path.startsWith(activeObjName)) {
  511. const [objName, fieldName] = path.split('.');
  512. // 拿到后端返回的原始字段值 (通常是字符串)
  513. const rawValue = formValue[objName]?.[fieldName];
  514. if (rawValue) {
  515. // 【核心修改】:调用你的解析函数,将字符串转为数组
  516. // 确保 unformatAttachment 函数已在当前作用域可用
  517. listMap[path] = unformatAttachment(rawValue);
  518. console.log(`附件解析成功 [${path}]:`, listMap[path]);
  519. }
  520. }
  521. });
  522. } catch (err) {
  523. console.error('详情加载失败:', err);
  524. ElMessage.error('详情回显失败');
  525. }
  526. };
  527. /**
  528. * 5. 提交保存
  529. */
  530. const handleSave = async () => {
  531. const valid = await formRef.value.validate().catch(() => false);
  532. if (!valid) return ElMessage.error('请检查表单必填项');
  533. loading.value = true;
  534. // 深度克隆,避免操作原对象
  535. const submitData = JSON.parse(JSON.stringify(formValue));
  536. // 数据清洗:只发送当前选中的危险作业详情
  537. const typeMap: any = { 1: 'space', 2: 'highAltitude', 3: 'electricityList', 4: 'hot' };
  538. const currentKey = typeMap[formValue.hazardOperationType];
  539. Object.values(typeMap).forEach((val) => {
  540. if (val !== currentKey) {
  541. delete submitData[val as string];
  542. }
  543. });
  544. dangerWorkUpdateDangerWork(submitData)
  545. .then(() => {
  546. ElMessage.success('保存成功');
  547. router.back();
  548. })
  549. .finally(() => {
  550. loading.value = false;
  551. });
  552. };
  553. /**
  554. * 辅助:表格行操作
  555. */
  556. const addRow = (type: 'measure' | 'analysis') => {
  557. if (type === 'measure') {
  558. formValue.measure.push({ serialNumber: formValue.measure.length + 1, safetyMeasure: '', confirmer: '' });
  559. } else {
  560. formValue.analysis.push({
  561. toxicSubstance: '',
  562. flammableGas: '',
  563. oxygenContent: '',
  564. analysisTime: '',
  565. analysisPosition: '',
  566. analyst: '',
  567. });
  568. }
  569. };
  570. const removeRow = (type: 'measure' | 'analysis', index: number) => {
  571. formValue[type].splice(index, 1);
  572. if (type === 'measure') {
  573. formValue.measure.forEach((item: any, i: number) => (item.serialNumber = i + 1));
  574. }
  575. };
  576. const handleChangeDept = () => {
  577. const node = cascaderRef.value?.getCheckedNodes()?.[0];
  578. if (node) {
  579. formValue.applicationDepartment = node.label;
  580. formValue.applicationDepartmentId = node.pathValues;
  581. }
  582. };
  583. onMounted(async () => {
  584. const [depts, approvals] = await Promise.all([getAllDepartments(), getAllApproval()]);
  585. firstLevelDepts.value = formatDeptTree(depts);
  586. approvalOptions.value = approvals || [];
  587. getDetail();
  588. });
  589. </script>
  590. <style lang="scss" scoped>
  591. @use '@/styles/page-main-layout.scss' as *;
  592. @use '@/styles/page-details-layout.scss' as *;
  593. .safety-platform-container {
  594. .section-title-flex {
  595. display: flex;
  596. justify-content: space-between;
  597. margin: 15px 0;
  598. }
  599. &__main {
  600. padding: 24px;
  601. background-color: #fff;
  602. }
  603. :deep(.el-form-item) {
  604. margin-right: 20px;
  605. margin-bottom: 24px;
  606. vertical-align: top;
  607. .el-form-item__label {
  608. font-weight: bold;
  609. }
  610. }
  611. }
  612. </style>