change.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  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" label-width="auto" :model="formValue" :rules="rules">
  11. <el-form-item label="楼号">
  12. <el-input v-model="formValue.buildingNo" disabled size="large" style="width: 50%" />
  13. </el-form-item>
  14. <el-form-item label="楼层">
  15. <el-input v-model="formValue.buildingArea" disabled size="large" style="width: 50%" />
  16. </el-form-item>
  17. <el-form-item label="房间/区域">
  18. <el-input v-model="formValue.floorRoomNo" disabled size="large" style="width: 50%" />
  19. </el-form-item>
  20. <el-form-item label="功能名称">
  21. <el-input v-model="formValue.nameFunction" disabled size="large" style="width: 50%" />
  22. </el-form-item>
  23. <el-form-item label="安全责任所/中心">
  24. <el-cascader
  25. v-model="formValue.safetyResponsibleCenterId"
  26. disabled
  27. style="width: 50%"
  28. size="large"
  29. :options="firstLevelDepts"
  30. :props="cascaderProp"
  31. :show-all-levels="false"
  32. clearable
  33. />
  34. </el-form-item>
  35. <el-form-item label="安全责任所/中心负责人">
  36. <el-select v-model="formValue.safetyCenterManager" disabled size="large" style="width: 50%">
  37. <el-option
  38. v-for="item in safetyCenterManagerOptions"
  39. :key="item.value"
  40. :label="item.label"
  41. :value="item.value"
  42. />
  43. </el-select>
  44. </el-form-item>
  45. <el-form-item label="安全责任部门">
  46. <el-cascader
  47. disabled
  48. v-model="formValue.safetyResponsibleDepartmentId"
  49. style="width: 50%"
  50. size="large"
  51. :options="firstLevelDepts"
  52. :props="cascaderProp"
  53. :show-all-levels="false"
  54. />
  55. </el-form-item>
  56. <el-form-item label="安全责任部门负责人">
  57. <el-select disabled v-model="formValue.safetyDepartmentManager" size="large" style="width: 50%">
  58. <el-option v-for="item in userOptions" :key="item.value" :label="item.label" :value="item.value" />
  59. </el-select>
  60. </el-form-item>
  61. <el-form-item label="安全具体责任人">
  62. <el-select disabled v-model="formValue.safetySpecificPerson" size="large" style="width: 50%">
  63. <el-option v-for="item in userOptions" :key="item.value" :label="item.label" :value="item.value" />
  64. </el-select>
  65. </el-form-item>
  66. <el-form-item label="安全具体责任人联系方式">
  67. <el-input disabled v-model="formValue.safetyPersonContact" size="large" style="width: 50%" />
  68. </el-form-item>
  69. <h5 style="margin: 30px 0; font-weight: bold; color: #409eff">信息变更</h5>
  70. <el-form-item label="变更后的安全责任部门" prop="safetyResponsibleDepartmentTodo">
  71. <el-cascader
  72. v-model="formValue.safetyResponsibleDepartmentIdTodo"
  73. style="width: 50%"
  74. size="large"
  75. :ref="(el) => (cascaderRef['safetyResponsibleDepartmentTodo'] = el)"
  76. :options="firstLevelDepts"
  77. :props="cascaderProp"
  78. :show-all-levels="false"
  79. placeholder="请选择新的责任部门"
  80. filterable
  81. clearable
  82. @change="(val) => handleChangeDept(val, 'safetyResponsibleDepartmentTodo')"
  83. />
  84. </el-form-item>
  85. <el-form-item label="变更后的安全具体责任人" prop="safetySpecificPersonTodo">
  86. <el-select
  87. :disabled="!todoUserOptions.length"
  88. v-model="formValue.safetySpecificPersonTodo"
  89. placeholder="请选择新的具体责任人"
  90. size="large"
  91. style="width: 50%"
  92. filterable
  93. clearable
  94. @change="(val) => syncUserName(todoUserOptions, val, 'safetySpecificPersonNameTodo')"
  95. >
  96. <el-option v-for="item in todoUserOptions" :key="item.value" :label="item.label" :value="item.value" />
  97. </el-select>
  98. </el-form-item>
  99. <el-form-item label="变更原因" prop="changeReason">
  100. <el-input
  101. v-model="formValue.changeReason"
  102. type="textarea"
  103. :rows="5"
  104. placeholder="请详细描述变更原因"
  105. style="width: 70%"
  106. maxlength="200"
  107. show-word-limit
  108. />
  109. </el-form-item>
  110. </el-form>
  111. </main>
  112. <footer class="safety-platform-container__footer">
  113. <el-button @click="$router.push({ name: 'areaResponsibilities:nonPublic' })">返回</el-button>
  114. <el-button type="primary" :loading="submiting" @click="handleSubmit">提交变更</el-button>
  115. </footer>
  116. </div>
  117. </template>
  118. <script lang="ts" setup>
  119. import { ref, reactive, onMounted, nextTick } from 'vue';
  120. import { useRouter, useRoute } from 'vue-router';
  121. import { ElMessage } from 'element-plus';
  122. import { getAllDepartments } from '@/api/auth/dept';
  123. import { formatDeptTree } from '@/views/disaster/utils/formatDeptTree';
  124. import {
  125. areaCheckListQueryDetail,
  126. areaCheckListChange,
  127. queryAvailableUserList,
  128. } from '@/api/production-safety/responsibility-implementation';
  129. const router = useRouter();
  130. const route = useRoute();
  131. const formRef = ref<any>(null);
  132. const submiting = ref(false);
  133. // 数据源
  134. const firstLevelDepts = ref<any[]>([]);
  135. const oldCenterManagerOptions = ref<any[]>([]); // 旧负责人数据源
  136. const todoUserOptions = ref<any[]>([]); // 新负责人下拉数据源
  137. const cascaderRef = ref({});
  138. const cascaderProp = { expandTrigger: 'click', checkStrictly: true, value: 'id', label: 'deptName' };
  139. const formValue = reactive({
  140. id: undefined,
  141. buildingNo: '',
  142. buildingArea: '',
  143. floorRoomNo: '',
  144. nameFunction: '',
  145. // 旧数据
  146. safetyResponsibleCenter: '',
  147. safetyResponsibleCenterId: [],
  148. safetyCenterManager: null as number | null,
  149. safetyResponsibleDepartment: '',
  150. safetyResponsibleDepartmentId: [],
  151. safetyDepartmentManager: null as number | null,
  152. safetySpecificPerson: null as number | null,
  153. safetyPersonContact: '',
  154. // 变更数据
  155. safetyResponsibleDepartmentTodo: '',
  156. safetyResponsibleDepartmentIdTodo: [],
  157. safetySpecificPersonTodo: null as number | null,
  158. safetySpecificPersonNameTodo: '',
  159. changeReason: '',
  160. });
  161. const rules = reactive({
  162. safetyResponsibleDepartmentTodo: [{ required: true, message: '请选择变更后的责任部门', trigger: 'change' }],
  163. safetySpecificPersonTodo: [{ required: true, message: '请选择变更后的具体责任人', trigger: 'change' }],
  164. changeReason: [{ required: true, message: '请输入变更原因', trigger: 'blur' }],
  165. });
  166. // 获取部门树
  167. const getDeptData = async () => {
  168. const res = await getAllDepartments();
  169. firstLevelDepts.value = formatDeptTree(res);
  170. };
  171. // 获取用户列表封装
  172. const getUserData = (optionList, deptName) => {
  173. return queryAvailableUserList({
  174. pageNumber: 1,
  175. pageSize: 200,
  176. queryParam: { deptName },
  177. }).then((res: any) => {
  178. optionList.value = (res.records || []).map((u: any) => ({
  179. value: u.id,
  180. label: u.realname,
  181. }));
  182. });
  183. };
  184. // 级联选择处理
  185. const handleChangeDept = (val, prop) => {
  186. const cascader = cascaderRef.value?.[prop];
  187. const deptInfo = cascader?.getCheckedNodes();
  188. if (deptInfo?.length) {
  189. formValue[prop] = deptInfo[0]?.label;
  190. formValue.safetySpecificPersonTodo = null;
  191. getUserData(todoUserOptions, deptInfo[0]?.label);
  192. }
  193. };
  194. const syncUserName = (optionList, id: number, nameField: string) => {
  195. const user = optionList.find((u) => u.value === id);
  196. if (user) formValue[nameField] = user.label;
  197. };
  198. // 详情回显
  199. // const handlAreaCheckListQueryDetail = async () => {
  200. // const id = route.query.id;
  201. // if (!id) return;
  202. // try {
  203. // const res: any = await areaCheckListQueryDetail({ id });
  204. // if (res) {
  205. // Object.assign(formValue, res);
  206. // // 1. 解析旧部门级联路径
  207. // if (typeof res.safetyResponsibleCenterId === 'string') {
  208. // formValue.safetyResponsibleCenterId = JSON.parse(res.safetyResponsibleCenterId);
  209. // }
  210. // // 2. 加载旧负责人列表以显示名称
  211. // if (formValue.safetyResponsibleCenter) {
  212. // getUserData(oldCenterManagerOptions, formValue.safetyResponsibleCenter);
  213. // }
  214. // // 3. 纠正 ID 类型
  215. // if (formValue.safetyCenterManager) formValue.safetyCenterManager = Number(formValue.safetyCenterManager);
  216. // }
  217. // } catch (err) {
  218. // ElMessage.error('加载详情失败');
  219. // }
  220. // };
  221. const safetyCenterManagerOptions = ref<any[]>([]);
  222. const userOptions = ref<any[]>([]);
  223. const handlAreaCheckListQueryDetail = async () => {
  224. const id = route.query.id;
  225. if (!id) return;
  226. try {
  227. const res: any = await areaCheckListQueryDetail({ id });
  228. if (res) {
  229. Object.assign(formValue, res);
  230. formValue.changeReason = ''; // 确保变更原因初始为空
  231. formValue.safetySpecificPersonTodo = null; // 确保变更具体
  232. formValue.safetyResponsibleDepartmentIdTodo = []; // 确保变更部门初始为空
  233. // 1. 解析级联 ID 数组
  234. try {
  235. if (typeof res.safetyResponsibleCenterId === 'string') {
  236. formValue.safetyResponsibleCenterId = JSON.parse(res.safetyResponsibleCenterId);
  237. }
  238. if (typeof res.safetyResponsibleDepartmentId === 'string') {
  239. formValue.safetyResponsibleDepartmentId = JSON.parse(res.safetyResponsibleDepartmentId);
  240. }
  241. } catch (e) {
  242. console.error('解析部门ID路径失败', e);
  243. }
  244. // 2. 类型转换
  245. formValue.safetyCenterManager = res.safetyCenterManager ? Number(res.safetyCenterManager) : null;
  246. formValue.safetyDepartmentManager = res.safetyDepartmentManager ? Number(res.safetyDepartmentManager) : null;
  247. formValue.safetySpecificPerson = res.safetySpecificPerson ? Number(res.safetySpecificPerson) : null;
  248. // 3. 补全人员名单以显示姓名
  249. if (formValue.safetyResponsibleCenter) {
  250. getUserData(safetyCenterManagerOptions, formValue.safetyResponsibleCenter);
  251. }
  252. if (formValue.safetyResponsibleDepartment) {
  253. getUserData(userOptions, formValue.safetyResponsibleDepartment);
  254. }
  255. if(formValue.safetySpecificPerson) {
  256. getUserData(userOptions, undefined);
  257. }
  258. }
  259. } catch (err) {
  260. ElMessage.error('获取详情失败');
  261. }
  262. };
  263. onMounted(async () => {
  264. await getDeptData();
  265. await handlAreaCheckListQueryDetail();
  266. });
  267. const handleSubmit = () => {
  268. formRef.value?.validate((valid: boolean) => {
  269. if (valid) {
  270. submiting.value = true;
  271. const submitData = {
  272. id: Number(route.query.id),
  273. safetyResponsibleDepartmentTodo: formValue.safetyResponsibleDepartmentTodo,
  274. safetyResponsibleDepartmentIdTodo: JSON.stringify(formValue.safetyResponsibleDepartmentIdTodo), // 根据接口需求决定是否 stringify
  275. safetySpecificPersonTodo: formValue.safetySpecificPersonTodo,
  276. safetySpecificPersonNameTodo: formValue.safetySpecificPersonNameTodo,
  277. changeReason: formValue.changeReason,
  278. };
  279. areaCheckListChange(submitData)
  280. .then(() => {
  281. ElMessage.success('变更申请提交成功!');
  282. router.push({ name: 'areaResponsibilities:nonPublic' });
  283. })
  284. .finally(() => (submiting.value = false));
  285. }
  286. });
  287. };
  288. </script>
  289. <style lang="scss" scoped>
  290. @use '@/styles/page-main-layout.scss' as *;
  291. @use '@/styles/page-details-layout.scss' as *;
  292. @use '@/styles/basic-table-action.scss' as *;
  293. </style>