add.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  1. <template>
  2. <div class="safety-platform-container">
  3. <header class="safety-platform-container__header">
  4. <div class="breadcrumb-title">
  5. <BreadcrumbBack />
  6. 新增风险清单
  7. </div>
  8. </header>
  9. <main class="safety-platform-container__main">
  10. <el-form ref="formRef" :inline="true" label-width="auto" :model="formValue" :rules="rules">
  11. <el-form-item label="楼号/区域" prop="buildingArea">
  12. <el-input v-model="formValue.buildingArea" size="large" placeholder="例如:A栋、东区" style="width: 330px" />
  13. </el-form-item>
  14. <el-form-item label="楼宇名称" prop="buildingName">
  15. <el-input
  16. v-model="formValue.buildingName"
  17. size="large"
  18. placeholder="例如:科研楼、实验中心"
  19. style="width: 330px"
  20. />
  21. </el-form-item>
  22. <el-form-item label="安全责任人" prop="safetyResponsibleBuilding">
  23. <el-select
  24. v-model="formValue.safetyResponsibleBuilding"
  25. placeholder="请选择楼宇安全责任人"
  26. size="large"
  27. :remote-method="changeUser"
  28. style="width: 330px"
  29. filterable
  30. remote
  31. >
  32. <el-option v-for="item in userOptions" :key="item.id" :label="item.name" :value="item.id" />
  33. </el-select>
  34. </el-form-item>
  35. <el-form-item label="楼层/位置" prop="floorLocation">
  36. <el-input
  37. v-model="formValue.floorLocation"
  38. size="large"
  39. placeholder="例如:3层、地下一层、走廊东侧"
  40. style="width: 330px"
  41. />
  42. </el-form-item>
  43. <el-form-item label="安全责任人" prop="safetyResponsibleFloor">
  44. <el-select
  45. v-model="formValue.safetyResponsibleFloor"
  46. placeholder="请选择楼层/位置安全责任人"
  47. size="large"
  48. :remote-method="changeUser"
  49. style="width: 330px"
  50. filterable
  51. remote
  52. >
  53. <el-option v-for="item in userOptions" :key="item.id" :label="item.name" :value="item.id" />
  54. </el-select>
  55. </el-form-item>
  56. <el-form-item label="房间号(名称)" prop="roomName">
  57. <el-input
  58. v-model="formValue.roomName"
  59. size="large"
  60. placeholder="例如:301、高压配电室"
  61. style="width: 330px"
  62. />
  63. </el-form-item>
  64. <el-form-item label="责任部门" prop="responsibleDepartment">
  65. <el-cascader
  66. style="width: 330px"
  67. v-model="formValue.responsibleDepartmentId"
  68. size="large"
  69. ref="cascaderRef"
  70. :options="firstLevelDepts"
  71. :props="cascaderProp"
  72. :show-all-levels="false"
  73. placeholder="请选择责任部门"
  74. filterable
  75. @change="handleChangeDept('responsibleDepartment')"
  76. />
  77. </el-form-item>
  78. <el-form-item label="安全责任人" prop="roomSafetyResponsible">
  79. <el-select
  80. v-model="formValue.roomSafetyResponsible"
  81. placeholder="请选择房间号安全责任人"
  82. size="large"
  83. style="width: 330px"
  84. :remote-method="remoteMethod"
  85. filterable
  86. remote
  87. >
  88. <el-option v-for="item in userList" :key="item.id" :label="item.name" :value="item.id" />
  89. </el-select>
  90. </el-form-item>
  91. <el-form-item label="是否存在风险点" prop="hasRiskPoint">
  92. <el-select
  93. v-model="formValue.hasRiskPoint"
  94. size="large"
  95. placeholder="请选择是否存有风险点"
  96. style="width: 330px"
  97. >
  98. <el-option label="是" :value="1" />
  99. <el-option label="否" :value="0" />
  100. </el-select>
  101. </el-form-item>
  102. <el-form-item label="风险点类别" prop="riskCategory">
  103. <el-select v-model="formValue.riskCategory" size="large" placeholder="请选择风险点类别" style="width: 330px">
  104. <el-option :value="1" label="III级危险点" />
  105. <el-option :value="2" label="II级危险点" />
  106. <el-option :value="3" label="I级危险点" />
  107. <el-option :value="4" label="UPS" />
  108. <el-option :value="5" label="电力设施(强电)" />
  109. <el-option :value="6" label="高低温气体液体、高压气体" />
  110. <el-option :value="7" label="试验设施设备" />
  111. <el-option :value="8" label="特种设备" />
  112. <el-option :value="9" label="危化品、易燃易爆固液气体" />
  113. <el-option :value="10" label="有限空间" />
  114. </el-select>
  115. </el-form-item>
  116. <el-form-item label="风险点名称" prop="riskPointName">
  117. <el-input
  118. v-model="formValue.riskPointName"
  119. size="large"
  120. placeholder="例如:液氮储罐、高压开关柜"
  121. style="width: 330px"
  122. />
  123. </el-form-item>
  124. <el-form-item label="风险点编号" prop="riskPointNumber">
  125. <el-input
  126. v-model="formValue.riskPointNumber"
  127. size="large"
  128. placeholder="请输入唯一风险点编号"
  129. style="width: 330px"
  130. />
  131. </el-form-item>
  132. <el-form-item label="风险点规格" prop="riskPointSpec">
  133. <el-input
  134. v-model="formValue.riskPointSpec"
  135. size="large"
  136. placeholder="例如:容量500L、电压10kV"
  137. style="width: 330px"
  138. />
  139. </el-form-item>
  140. <el-form-item label="培训要求" prop="trainingRequirement">
  141. <el-input
  142. v-model="formValue.trainingRequirement"
  143. size="large"
  144. placeholder="例如:持证上岗、年度复训"
  145. style="width: 330px"
  146. />
  147. </el-form-item>
  148. <el-form-item label="安全风险" prop="safetyRisk">
  149. <el-input
  150. v-model="formValue.safetyRisk"
  151. size="large"
  152. placeholder="描述该风险点可能引发的安全问题"
  153. style="width: 330px"
  154. />
  155. </el-form-item>
  156. <el-form-item label="可能造成伤害" prop="possibleHarm">
  157. <el-input
  158. v-model="formValue.possibleHarm"
  159. size="large"
  160. placeholder="例如:爆炸、中毒、触电、窒息等"
  161. style="width: 330px"
  162. />
  163. </el-form-item>
  164. <el-form-item label="主要管控措施" prop="mainControlMeasures">
  165. <el-input
  166. v-model="formValue.mainControlMeasures"
  167. size="large"
  168. placeholder="例如:定期巡检、设置警示标识、配备防护装备"
  169. style="width: 330px"
  170. />
  171. </el-form-item>
  172. <el-form-item label="目前是否存在安全隐患" prop="currentHazard">
  173. <el-input
  174. v-model="formValue.currentHazard"
  175. size="large"
  176. placeholder="例如:设备老化、线路裸露、通风不良"
  177. style="width: 330px"
  178. />
  179. </el-form-item>
  180. <el-form-item label="隐患内容" prop="hazardContent">
  181. <el-input
  182. v-model="formValue.hazardContent"
  183. size="large"
  184. placeholder="详细描述当前存在的隐患情况"
  185. style="width: 330px"
  186. />
  187. </el-form-item>
  188. <el-form-item label="应急预案名称" prop="emergencyPlanName">
  189. <el-input
  190. v-model="formValue.emergencyPlanName"
  191. size="large"
  192. placeholder="例如:《危化品泄漏应急处置预案》"
  193. style="width: 330px"
  194. />
  195. </el-form-item>
  196. <el-form-item label="应急预案编号" prop="emergencyPlanNumber">
  197. <el-input
  198. v-model="formValue.emergencyPlanNumber"
  199. size="large"
  200. placeholder="例如:YJYA-2024-001"
  201. style="width: 330px"
  202. />
  203. </el-form-item>
  204. <el-form-item label="演练计划及实施情况" prop="rectificationPlan">
  205. <el-input
  206. v-model="formValue.rectificationPlan"
  207. size="large"
  208. placeholder="例如:每季度演练一次,最近一次于2025年12月完成"
  209. style="width: 330px"
  210. />
  211. </el-form-item>
  212. <el-form-item label="风险等级" prop="riskLevel">
  213. <el-select v-model="formValue.riskLevel" size="large" placeholder="请选择风险等级" style="width: 330px">
  214. <el-option :value="1" label="高" />
  215. <el-option :value="2" label="中" />
  216. <el-option :value="3" label="低" />
  217. </el-select>
  218. </el-form-item>
  219. <el-form-item>
  220. <div style="width: 330px"></div>
  221. </el-form-item>
  222. <el-form-item label="备注" prop="remarks" style="width: 87.2%">
  223. <el-input
  224. type="textarea"
  225. v-model="formValue.remarks"
  226. size="large"
  227. :rows="7"
  228. placeholder="可填写其他补充说明"
  229. />
  230. </el-form-item>
  231. </el-form>
  232. </main>
  233. <footer class="safety-platform-container__footer">
  234. <el-button @click="$router.push({ name: 'riskManage' })">返回</el-button>
  235. <el-button type="primary" :loading="submiting" @click="handleSubmit">提交</el-button>
  236. </footer>
  237. </div>
  238. </template>
  239. <script lang="ts" setup>
  240. import { ref, reactive, onMounted, nextTick } from 'vue';
  241. import { useRouter } from 'vue-router';
  242. import { ElMessage } from 'element-plus';
  243. import { getAllDepartments } from '@/api/auth/dept';
  244. import { formatDeptTree } from '@/views/disaster/utils/formatDeptTree';
  245. import {
  246. queryAvailableUserList,
  247. safetyRiskListSaveRiskList,
  248. } from '@/api/production-safety/responsibility-implementation';
  249. const router = useRouter();
  250. const formRef = ref<any>(null);
  251. const submiting = ref(false);
  252. const userOptions = ref<any[]>([]);
  253. const userList = ref<any[]>([]);
  254. const firstLevelDepts = ref<any[]>([]);
  255. const cascaderProp = {
  256. expandTrigger: 'click',
  257. checkStrictly: true,
  258. value: 'id',
  259. label: 'deptName',
  260. };
  261. const cascaderRef = ref<any>();
  262. const formValue = reactive({
  263. buildingArea: '',
  264. buildingName: '',
  265. safetyResponsibleBuilding: '',
  266. floorLocation: '',
  267. safetyResponsibleFloor: '',
  268. roomName: '',
  269. responsibleDepartment: '',
  270. roomSafetyResponsible: '',
  271. hasRiskPoint: '',
  272. riskCategory: '',
  273. riskPointName: '',
  274. riskPointNumber: '',
  275. riskPointSpec: '',
  276. trainingRequirement: '',
  277. safetyRisk: '',
  278. possibleHarm: '',
  279. mainControlMeasures: '',
  280. currentHazard: '',
  281. hazardContent: '',
  282. emergencyPlanName: '',
  283. emergencyPlanNumber: '',
  284. rectificationPlan: '',
  285. riskLevel: '',
  286. remarks: '',
  287. responsibleDepartmentId: [],
  288. });
  289. const rules = reactive({
  290. buildingArea: [{ required: true, message: '请输入楼号', trigger: 'blur' }],
  291. buildingName: [{ required: true, message: '请输入楼宇/区域', trigger: 'blur' }],
  292. // safetyResponsibleBuilding: [{ required: true, message: '请输入楼层/房号', trigger: 'blur' }], 改为非必填
  293. floorLocation: [{ required: true, message: '请输入名称/功能', trigger: 'blur' }],
  294. safetyResponsibleFloor: [{ required: true, message: '请选择安全责任所/中心', trigger: 'change' }],
  295. roomName: [{ required: true, message: '请选择安全责任所/中心负责人', trigger: 'change' }],
  296. responsibleDepartment: [{ required: true, message: '请选择安全责任部门', trigger: 'change' }],
  297. roomSafetyResponsible: [{ required: true, message: '请输入房间安全责任人', trigger: 'blur' }],
  298. hasRiskPoint: [{ required: true, message: '请选择是否有风险点', trigger: 'change' }],
  299. riskCategory: [{ required: true, message: '请选择风险类别', trigger: 'change' }],
  300. riskPointName: [{ required: true, message: '请输入风险点名称', trigger: 'blur' }],
  301. riskPointNumber: [{ required: true, message: '请输入风险点编号', trigger: 'blur' }],
  302. riskPointSpec: [{ required: true, message: '请输入风险点规格/参数', trigger: 'blur' }],
  303. trainingRequirement: [{ required: true, message: '请输入培训要求', trigger: 'blur' }],
  304. safetyRisk: [{ required: true, message: '请输入安全风险描述', trigger: 'blur' }],
  305. possibleHarm: [{ required: true, message: '请输入可能造成的伤害', trigger: 'blur' }],
  306. mainControlMeasures: [{ required: true, message: '请输入主要控制措施', trigger: 'blur' }],
  307. currentHazard: [{ required: true, message: '请选择当前隐患状态', trigger: 'change' }],
  308. hazardContent: [{ required: true, message: '请输入隐患内容', trigger: 'blur' }],
  309. emergencyPlanName: [{ required: true, message: '请输入应急预案名称', trigger: 'blur' }],
  310. emergencyPlanNumber: [{ required: true, message: '请输入应急预案编号', trigger: 'blur' }],
  311. rectificationPlan: [{ required: true, message: '请输入整改方案', trigger: 'blur' }],
  312. riskLevel: [{ required: true, message: '请选择风险等级', trigger: 'change' }],
  313. remarks: [],
  314. });
  315. const changeDept = ref('')
  316. const handleChangeDept = (prop) => {
  317. const cascader = cascaderRef.value;
  318. const deptInfo = cascader?.getCheckedNodes();
  319. formValue[prop] = deptInfo[0].label;
  320. formRef.value.validateField(prop);
  321. changeDept.value = deptInfo[0].label
  322. nextTick(() => {
  323. handleQueryAvailableUserList(deptInfo[0].label, prop);
  324. });
  325. };
  326. const getDeptData = () => {
  327. getAllDepartments().then((res) => {
  328. firstLevelDepts.value = formatDeptTree(res);
  329. });
  330. };
  331. const remoteMethod = (realname)=>{
  332. handleQueryAvailableUserList(changeDept.value,realname)
  333. }
  334. const handleQueryAvailableUserList = (deptName, realname = '') => {
  335. queryAvailableUserList({
  336. pageNumber: 1,
  337. pageSize: 20,
  338. queryParam: {
  339. deptName,
  340. realname,
  341. },
  342. }).then((res: any) => {
  343. userList.value = (res.records || []).map((u: any) => ({
  344. id: u.id,
  345. name: u.realname,
  346. }));
  347. });
  348. };
  349. // 选择责任人
  350. const changeUser = (value)=>{
  351. getUserData(value)
  352. }
  353. const getUserData = (realname) => {
  354. queryAvailableUserList({ pageNumber: 1, pageSize: 20, queryParam: {
  355. realname
  356. } }).then((res: any) => {
  357. userOptions.value = (res.records || []).map((u: any) => ({
  358. id: u.id,
  359. name: u.realname,
  360. }));
  361. });
  362. };
  363. onMounted(() => {
  364. getDeptData();
  365. handleQueryAvailableUserList('');
  366. getUserData('');
  367. });
  368. const handleSubmit = () => {
  369. formRef.value?.validate((valid: boolean) => {
  370. if (valid) {
  371. submiting.value = true;
  372. safetyRiskListSaveRiskList({
  373. ...formValue,
  374. responsibleDepartmentId: formValue.responsibleDepartmentId.join(','),
  375. })
  376. .then(() => {
  377. ElMessage.success('创建成功!');
  378. router.push({ name: 'riskManage' });
  379. })
  380. .finally(() => {
  381. submiting.value = false;
  382. });
  383. }
  384. });
  385. };
  386. </script>
  387. <style lang="scss" scoped>
  388. @use '@/styles/page-main-layout.scss' as *;
  389. @use '@/styles/page-details-layout.scss' as *;
  390. @use '@/styles/basic-table-action.scss' as *;
  391. .editor-container {
  392. border: 1px solid #dcdfe6;
  393. border-radius: 4px;
  394. margin-right: 20px;
  395. overflow: hidden;
  396. // :deep(.w-e-text-container) {
  397. // min-height: 400px;
  398. // overflow-y: auto;
  399. // }
  400. }
  401. // :deep(.breadcrumb .title) {
  402. // margin-left: 0;
  403. // }
  404. // .main {
  405. // display: flex;
  406. // flex-direction: column;
  407. // padding: 20px;
  408. // flex: 1;
  409. // overflow: hidden;
  410. // background-color: #fff;
  411. // }
  412. // .button-content {
  413. // margin-bottom: 20px;
  414. // }
  415. // .page-content {
  416. // display: flex;
  417. // justify-content: flex-end;
  418. // }
  419. // // :deep(.el-form) {
  420. // // flex: 1;
  421. // // overflow: hidden;
  422. // // overflow-y: auto;
  423. // // }
  424. </style>