فهرست منبع

feat: 新增变更记录,优化确认变更流程

sunqijun 1 ماه پیش
والد
کامیت
ac5fe329f1

+ 8 - 1
src/api/equipment-high-alert-List/index.ts

@@ -2,7 +2,7 @@
  * @Author: liuJie
  * @Date: 2026-03-12 16:06:18
  * @LastEditors: liuJie
- * @LastEditTime: 2026-03-19 17:19:27
+ * @LastEditTime: 2026-03-20 16:35:34
  * @Describe: 告警列表
  */
 import { http } from '@/utils/http/axios';
@@ -27,6 +27,12 @@ export interface QueryParamType {
       endTime: string | undefined,
     };
   }
+
+  export interface DeviceType {
+    code: string;
+    id: string;
+    name: string;
+  }
   // 列表数据
 export const equipmentHighAlertList = (query: QueryParamType)=>{
   return http.request({
@@ -35,6 +41,7 @@ export const equipmentHighAlertList = (query: QueryParamType)=>{
     data: query,
   });
 }
+
   // 设备类型
 export const DeviceTypeList = ()=>{
   return http.request({

+ 1 - 2
src/api/production-education-training-plan/index.ts

@@ -77,9 +77,8 @@ export function issueEducationAndTrainingProgram(data: any) {
  */
 export function cancelEducationAndTrainingProgram(data: any) {
   return http.request({
-    url: '/educationTrainingPlan/cancel',
+    url: `/educationTrainingPlan/cancel?detid=${data.detid}&mid=${data.mid}`,
     method: 'put',
-    data,
   });
 }
 

+ 1 - 1
src/api/production-safety/responsibility-implementation/index.ts

@@ -261,7 +261,7 @@ export function areaCheckListQueryPage(params) {
 export function queryChangedList(params) {
   return http.request({
     url: '/areaCheckList/queryChangedList',
-    method: 'get',
+    method: 'post',
     params
   });
 }

+ 328 - 0
src/views/production-safety/implement-safety-duty/non-public-area-responsibilities/confirmChange.vue

@@ -0,0 +1,328 @@
+<template>
+<div class='content'>
+    <el-dialog title="确认变更" width="70%" v-model="changedDialogState" @open="openDialog" @close="cancel">
+        <main class="safety-platform-container__main">
+            <el-form ref="formRef" label-width="auto" :model="formValue" :rules="rules">
+                <el-form-item label="楼宇/区域" prop="buildingArea">
+                <el-input v-model="formValue.buildingArea" size="large" disabled placeholder="请输入楼宇/区域" />
+                </el-form-item>
+                <el-form-item label="楼层/房号" prop="floorRoomNo">
+                <el-input v-model="formValue.floorRoomNo" size="large" disabled placeholder="请输入楼层/房号" />
+                </el-form-item>
+                <el-form-item label="名称/功能" prop="nameFunction">
+                <el-input v-model="formValue.nameFunction" size="large" disabled placeholder="请输入名称/功能"  />
+                </el-form-item>
+
+                <el-form-item label="安全责任所/中心" prop="safetyResponsibleCenter">
+                <el-cascader
+                    v-model="formValue.safetyResponsibleCenterId"
+                    size="large"
+                    style="width:100%"
+                    :ref="(el) => (cascaderRef['safetyResponsibleCenter'] = el)"
+                    :options="firstLevelDepts"
+                    :props="cascaderProp"
+                    :show-all-levels="false"
+                    placeholder="请选择安全责任所/中心"
+                    filterable
+                    clearable
+                    @change="(val) => handleChangeDept(val, 'safetyResponsibleCenter')"
+                />
+                </el-form-item>
+
+                <el-form-item label="安全责任所/中心负责人" prop="safetyCenterManager">
+                <el-select
+                    v-model="formValue.safetyCenterManager"
+                    placeholder="请选择安全责任所/中心负责人"
+                    size="large"
+                    filterable
+                    style="width:100%"
+                    @change="(val) => syncUserName(safetyCenterManagerOptions, val, 'safetyCenterManagerName')"
+                >
+                    <el-option
+                    v-for="item in safetyCenterManagerOptions"
+                    :key="item.value"
+                    :label="item.label"
+                    :value="item.value"
+                    />
+                </el-select>
+                </el-form-item>
+
+                <el-form-item label="安全责任部门" prop="safetyResponsibleDepartment">
+                <el-cascader
+                    v-model="formValue.safetyResponsibleDepartmentId"
+                    size="large"
+                    :ref="(el) => (cascaderRef['safetyResponsibleDepartment'] = el)"
+                    :options="firstLevelDepts"
+                    :props="cascaderProp"
+                    :show-all-levels="false"
+                    placeholder="请选择安全责任部门"
+                    filterable
+                    clearable
+                    style="width:100%"
+                    @change="(val) => handleChangeDept(val, 'safetyResponsibleDepartment')"
+                />
+                </el-form-item>
+
+                <el-form-item label="安全责任部门负责人" prop="safetyDepartmentManager">
+                <el-select
+                    v-model="formValue.safetyDepartmentManager"
+                    placeholder="请选择安全责任部门负责人"
+                    size="large"
+                    filterable
+                    style="width:100%"
+                    @change="(val) => syncUserName(safetyDepartmentManagerOptions, val, 'safetyDepartmentManagerName')">
+                    <el-option v-for="item in safetyDepartmentManagerOptions" :key="item.value" :label="item.label" :value="item.value" />
+                </el-select>
+                </el-form-item>
+
+                <el-form-item label="安全具体责任人" prop="safetySpecificPerson">
+                <el-select
+                    v-model="formValue.safetySpecificPerson"
+                    placeholder="请选择安全具体责任人"
+                    size="large"
+                    disabled
+                    filterable
+                    style="width:100%"
+                    @change="(val) => syncUserName(userOptions, val, 'safetySpecificPersonName')"
+                >
+                    <el-option v-for="item in userOptions" :key="item.value" :label="item.label" :value="item.value" />
+                </el-select>
+                </el-form-item>
+
+                <el-form-item label="安全具体责任人联系方式" prop="safetyPersonContact">
+                <el-input
+                    v-model="formValue.safetyPersonContact"
+                    size="large"
+                    disabled
+                    placeholder="选择安全具体责任人联系方式"
+                />
+                </el-form-item>
+            </el-form>
+            </main>
+            <template #footer>
+                <el-button @click="cancel">返回</el-button>
+                <el-button type="primary" :loading="submiting" @click="handleSubmit">提交</el-button>
+            </template>
+    </el-dialog>
+</div>
+</template>
+
+
+<script lang="ts" setup>
+  import { ref, reactive, onMounted, nextTick, watch } from 'vue';
+  import { useRouter, useRoute } from 'vue-router';
+  import { ElMessage } from 'element-plus';
+  import { getAllDepartments } from '@/api/auth/dept';
+  import { formatDeptTree } from '@/views/disaster/utils/formatDeptTree';
+  import {
+    areaCheckListQueryDetail,
+    areaCheckListUpdateArea,
+    queryAvailableUserList,
+    areaCheckListApprove
+  } from '@/api/production-safety/responsibility-implementation';
+
+  const router = useRouter();
+  const route = useRoute();
+  const formRef = ref<any>(null);
+  const submiting = ref(false);
+  const props = defineProps({
+    visible: {
+        type: Boolean,
+        default: false
+    },
+    params: {
+        type:Object,
+        default: {
+          id: '',
+          approveType: ''
+        }
+    }
+  })
+
+  const changedDialogState = ref(false)
+  const emit = defineEmits(['confirm', 'cancel'])
+
+  const userOptions = ref<any[]>([]);
+  const safetyCenterManagerOptions = ref<any[]>([]);
+  const firstLevelDepts = ref<any[]>([]);
+  const safetyDepartmentManagerOptions = ref<any[]>([]);
+  const cascaderRef = ref({});
+  const cascaderProp = { expandTrigger: 'click', checkStrictly: true, value: 'id', label: 'deptName' };
+  watch(()=>props.visible,(newValue)=>{
+    changedDialogState.value = newValue
+  })
+  const formValue = reactive({
+    id: props.params.id,
+    buildingNo: '',
+    buildingArea: '',
+    floorRoomNo: '',
+    nameFunction: '',
+    safetyResponsibleCenter: '',
+    safetyResponsibleCenterId: [],
+    safetyCenterManager: null as number | null,
+    safetyCenterManagerName: '',
+    safetyResponsibleDepartment: '',
+    safetyResponsibleDepartmentId: [],
+    safetyDepartmentManager: null as number | null,
+    safetyDepartmentManagerName: '',
+    safetySpecificPerson: null as number | null,
+    safetySpecificPersonName: '',
+    safetyPersonContact: '',
+  });
+
+  const rules = reactive({
+    buildingArea: [{ required: true, message: '请输入楼宇/区域' }],
+    floorRoomNo: [{ required: true, message: '请输入楼层/房号' }],
+    nameFunction: [{ required: true, message: '请输入名称/功能' }],
+    safetyResponsibleCenter: [{ required: true, message: '请选择安全责任所/中心', trigger: 'change'}],
+    safetyCenterManager: [{ required: true, message: '请选择负责人', trigger: 'change' }],
+    safetyResponsibleDepartment: [{ required: true, message: '请选择安全责任部门', trigger: 'change' }],
+    safetyDepartmentManager: [{ required: true, message: '请选择负责人', trigger: 'change' }],
+    safetySpecificPerson: [{ required: true, message: '请选择安全具体责任人', trigger: 'change' }],
+    safetyPersonContact: [
+      { required: true, message: '请输入联系方式' },
+      { pattern: /^1[3-9]\d{9}$/, message: '格式不正确' },
+    ],
+  });
+
+  const cancel = ()=>{
+    submiting.value = false;
+    emit('cancel', false)
+  }
+  const getDeptData = () => {
+    getAllDepartments().then((res) => {
+      firstLevelDepts.value = formatDeptTree(res);
+    });
+  };
+
+  const getUserData = (optionList, deptName) => {
+    console.log('deptName', deptName)
+    return queryAvailableUserList({
+      pageNumber: 1,
+      pageSize: 2000,
+      queryParam: { deptName },
+    }).then((res: any) => {
+      optionList.value = (res.records || []).map((u: any) => ({
+        value: u.id,
+        label: u.realname,
+        mobile: u.mobile,
+      }));
+    });
+  };
+
+  const handleChangeDept = (val, prop) => {
+    const cascader = cascaderRef.value?.[prop];
+    const deptInfo = cascader?.getCheckedNodes();
+    if (deptInfo?.length) {
+      formValue[prop] = deptInfo[0]?.label;
+      handleQueryAvailableUserList(deptInfo[0]?.label, prop);
+    }
+  };
+
+  const handleQueryAvailableUserList = (value, prop) => {
+    if (prop === 'safetyResponsibleCenter') {
+      formValue.safetyCenterManager = null;
+      getUserData(safetyCenterManagerOptions, value);
+    } else if(prop === 'safetyResponsibleDepartment'){
+      formValue.safetyDepartmentManager = null;
+      getUserData(safetyDepartmentManagerOptions, value);
+    } else {
+    //   formValue.safetySpecificPerson = null;
+      formValue.safetyDepartmentManager = null;
+      getUserData(userOptions, value);
+    }
+  };
+
+  const syncUserName = (optionList, id, nameField) => {
+    const user = optionList.find((u) => u.value === id);
+    if (user) {
+      formValue[nameField] = user.label;
+      if (nameField === 'safetySpecificPersonName') formValue.safetyPersonContact = user.mobile;
+    }
+  };
+
+  const handlAreaCheckListQueryDetail = async () => {
+    const id = props.params.id;
+    if (!id) return;
+
+    try {
+      const res: any = await areaCheckListQueryDetail({ id });
+      if (res) {
+        // 1. 基础赋值
+        Object.assign(formValue, res);
+
+        // 2. 解析 JSON 字符串格式的 ID 数组
+        try {
+          if (typeof res.safetyResponsibleCenterId === 'string') {
+            formValue.safetyResponsibleCenterId = [] //JSON.parse(res.safetyResponsibleCenterId);
+          }
+          if (typeof res.safetyResponsibleDepartmentId === 'string') {
+            formValue.safetyResponsibleDepartmentId =  [] //JSON.parse(res.safetyResponsibleDepartmentId);
+          }
+        } catch (e) {
+          console.error('ID数组解析失败', e);
+        }
+
+        // 3. ID 类型纠正 (String to Number)
+        formValue.safetyCenterManager = null // res.safetyCenterManager ? Number(res.safetyCenterManager) : null;
+        formValue.safetyDepartmentManager = null //res.safetyDepartmentManager ? Number(res.safetyDepartmentManager) : null;
+        formValue.safetySpecificPerson = res.safetySpecificPerson ? Number(res.safetySpecificPerson) : null;
+
+        // 4. 立即同步加载人员列表,防止页面初次显示 ID 数字
+        // if (formValue.safetyResponsibleCenter) {
+        //   getUserData(safetyCenterManagerOptions, formValue.safetyResponsibleCenter);
+        // }
+        
+        // if (formValue.safetyResponsibleDepartment) {
+        //   getUserData(userOptions, formValue.safetyResponsibleDepartment);
+        // }
+        if(formValue.safetySpecificPerson) {
+            getUserData(userOptions, undefined);
+        }
+      }
+    } catch (err) {
+      ElMessage.error('详情获取失败');
+    }
+  };
+  const openDialog = async ()=>{
+    nextTick()
+    submiting.value = false;
+    await getDeptData();
+    await handlAreaCheckListQueryDetail();
+  }
+
+  const handleSubmit = () => {
+    formRef.value?.validate((valid) => {
+      if (valid) {
+        submiting.value = true;
+        // 提交时后端通常接受字符串形式,如果后端要数组,则直接传 formValue
+            console.log(formValue, '参数');
+            areaCheckListApprove({
+              approveType: 1,
+              refuseReason: null,
+              ...formValue,
+            }).then((res) => {
+                ElMessage.success('操作成功!');
+            }).finally(() => {
+                submiting.value = false
+                emit('confirm')
+            });
+      }
+    });
+  };
+</script>
+<style lang="scss" scoped>
+  @use '@/styles/page-main-layout.scss' as *;
+  @use '@/styles/page-details-layout.scss' as *;
+  @use '@/styles/basic-table-action.scss' as *;
+
+  .editor-container {
+    border: 1px solid #dcdfe6;
+    border-radius: 4px;
+    margin-right: 20px;
+    overflow: hidden;
+  }
+  :deep(.el-form-item){
+    width: 80%;
+  }
+</style>

+ 65 - 14
src/views/production-safety/implement-safety-duty/non-public-area-responsibilities/list.vue

@@ -180,8 +180,22 @@
                 <el-table-column label="变更原因" show-overflow-tooltip prop="changeReason" width="170" />
                 <el-table-column label="状态" prop="statusName" width="100" />
             </el-table>
+            <div class="pagination-container" v-if="changedListData.historiesRecords.totalRow > 0">
+                <el-pagination
+                    background
+                    layout="prev, pager, next, jumper,sizes, total"
+                    :current-page="queryParams.pageNumber"
+                    :page-size="queryParams.pageSize"
+                    :total="changedListData.historiesRecords.totalRow"
+                    :page-sizes="[10, 20, 50, 100]"
+                    @size-change="handleSizeChange2"
+                    @current-change="handleCurrentChange2"
+                />
+            </div>
         </div>
     </el-dialog>
+    <!-- 确认弹窗 -->
+    <confirmChange :visible="changedDialogState" :params="changedParams" @confirm="handleConfirmChange" @cancel="handleCancelChange" />
   </div>
   <BatchImport
     :visible="batchImportVisible"
@@ -238,21 +252,37 @@
     batchImportVisible.value = false;
     queryTableList();
   };
-  const changedVisible = ref(false)
+const changedVisible = ref(false)
   const changedListData = reactive({
   currentRecord:[],
-  historiesRecords:[]
+  historiesRecords: {
+    maxPageSize: 0,
+    optimizeCountQuery: true,
+    pageNumber: 1,
+    pageSize: 10,
+    records: [],
+    totalPage: 1,
+    totalRow: 1
+  }
 })
+  const fetchParams = reactive({
+    pageNumber: 1,
+    pageSize: 10,
+    queryParam: {
+        id:''
+    }
+  }) 
   const changedList = async(item)=>{
-    await fetchTableList(item.id)
+    fetchParams.queryParam.id = item.id
+    await fetchTableList()
     changedVisible.value = true
   }
-  const fetchTableList = async (id)=>{
-    let res = await queryChangedList({id})
+  const fetchTableList = async ()=>{
+    let res = await queryChangedList(fetchParams)
     if(!res){ return }
     Object.assign(changedListData, {
         currentRecord: res.currentRecord || [],
-        historiesRecords: res.historiesRecords || []
+        historiesRecords: res.historiesRecords
     })
   }
   const tableData = reactive({
@@ -284,21 +314,35 @@
       console.log(e);
     }
   }
-
+  const changedDialogState = ref(false)
+  
+  const changedParams = reactive({})
+  // 弹出弹窗,修改必填项
   const handleAreaCheckListApprove = (scope, approveType) => {
+    if(approveType===1){
+        changedDialogState.value = true
+        Object.assign(changedParams, {
+            id: scope.row.id,
+            approveType
+        })
+        return 
+    }
     areaCheckListApprove({
       id: scope.row.id,
       approveType,
       refuseReason: null,
-    }).then(() => {
-      if (approveType === 1) {
-        ElMessage.success('请尽快修改该责任清单的安全责任所/中心、安全责任部门及相关负责人信息');
-      } else {
-        ElMessage.success('操作成功!');
-      }
+    }).then((res) => {
+      ElMessage.success('操作成功!');
       queryTableList();
     });
   };
+  // 确认回调
+  const handleConfirmChange = ()=>{
+    changedDialogState.value = false
+  }
+  const handleCancelChange = ()=>{
+    changedDialogState.value = false
+  }
 
   const handleSizeChange = (value) => {
     queryParams.pageSize = value;
@@ -308,7 +352,14 @@
     queryParams.pageNumber = value;
     queryTableList();
   };
-
+  const handleSizeChange2 = (value) => {
+    fetchParams.pageSize = value;
+    fetchTableList()
+  };
+  const handleCurrentChange2 = (value) => {
+    fetchParams.pageNumber = value;
+    fetchTableList()
+  };
   const handleConfirmDeleteRow = (scope) => {
     areaCheckListDelete(scope.row.id).then(() => {
       ElMessage.success('删除成功!');

+ 328 - 0
src/views/production-safety/implement-safety-duty/non-public-list-responsibilities/confirmChange.vue

@@ -0,0 +1,328 @@
+<template>
+<div class='content'>
+    <el-dialog title="确认变更" width="70%" v-model="changedDialogState" @open="openDialog" @close="cancel">
+        <main class="safety-platform-container__main">
+            <el-form ref="formRef" label-width="auto" :model="formValue" :rules="rules">
+                <el-form-item label="楼宇/区域" prop="buildingArea">
+                <el-input v-model="formValue.buildingArea" size="large" disabled placeholder="请输入楼宇/区域" />
+                </el-form-item>
+                <el-form-item label="楼层/房号" prop="floorRoomNo">
+                <el-input v-model="formValue.floorRoomNo" size="large" disabled placeholder="请输入楼层/房号" />
+                </el-form-item>
+                <el-form-item label="名称/功能" prop="nameFunction">
+                <el-input v-model="formValue.nameFunction" size="large" disabled placeholder="请输入名称/功能"  />
+                </el-form-item>
+
+                <el-form-item label="安全责任所/中心" prop="safetyResponsibleCenter">
+                <el-cascader
+                    v-model="formValue.safetyResponsibleCenterId"
+                    size="large"
+                    style="width:100%"
+                    :ref="(el) => (cascaderRef['safetyResponsibleCenter'] = el)"
+                    :options="firstLevelDepts"
+                    :props="cascaderProp"
+                    :show-all-levels="false"
+                    placeholder="请选择安全责任所/中心"
+                    filterable
+                    clearable
+                    @change="(val) => handleChangeDept(val, 'safetyResponsibleCenter')"
+                />
+                </el-form-item>
+
+                <el-form-item label="安全责任所/中心负责人" prop="safetyCenterManager">
+                <el-select
+                    v-model="formValue.safetyCenterManager"
+                    placeholder="请选择安全责任所/中心负责人"
+                    size="large"
+                    filterable
+                    style="width:100%"
+                    @change="(val) => syncUserName(safetyCenterManagerOptions, val, 'safetyCenterManagerName')"
+                >
+                    <el-option
+                    v-for="item in safetyCenterManagerOptions"
+                    :key="item.value"
+                    :label="item.label"
+                    :value="item.value"
+                    />
+                </el-select>
+                </el-form-item>
+
+                <el-form-item label="安全责任部门" prop="safetyResponsibleDepartment">
+                <el-cascader
+                    v-model="formValue.safetyResponsibleDepartmentId"
+                    size="large"
+                    :ref="(el) => (cascaderRef['safetyResponsibleDepartment'] = el)"
+                    :options="firstLevelDepts"
+                    :props="cascaderProp"
+                    :show-all-levels="false"
+                    placeholder="请选择安全责任部门"
+                    filterable
+                    clearable
+                    style="width:100%"
+                    @change="(val) => handleChangeDept(val, 'safetyResponsibleDepartment')"
+                />
+                </el-form-item>
+
+                <el-form-item label="安全责任部门负责人" prop="safetyDepartmentManager">
+                <el-select
+                    v-model="formValue.safetyDepartmentManager"
+                    placeholder="请选择安全责任部门负责人"
+                    size="large"
+                    filterable
+                    style="width:100%"
+                    @change="(val) => syncUserName(safetyDepartmentManagerOptions, val, 'safetyDepartmentManagerName')">
+                    <el-option v-for="item in safetyDepartmentManagerOptions" :key="item.value" :label="item.label" :value="item.value" />
+                </el-select>
+                </el-form-item>
+
+                <el-form-item label="安全具体责任人" prop="safetySpecificPerson">
+                <el-select
+                    v-model="formValue.safetySpecificPerson"
+                    placeholder="请选择安全具体责任人"
+                    size="large"
+                    disabled
+                    filterable
+                    style="width:100%"
+                    @change="(val) => syncUserName(userOptions, val, 'safetySpecificPersonName')"
+                >
+                    <el-option v-for="item in userOptions" :key="item.value" :label="item.label" :value="item.value" />
+                </el-select>
+                </el-form-item>
+
+                <el-form-item label="安全具体责任人联系方式" prop="safetyPersonContact">
+                <el-input
+                    v-model="formValue.safetyPersonContact"
+                    size="large"
+                    disabled
+                    placeholder="选择安全具体责任人联系方式"
+                />
+                </el-form-item>
+            </el-form>
+            </main>
+            <template #footer>
+                <el-button @click="cancel">返回</el-button>
+                <el-button type="primary" :loading="submiting" @click="handleSubmit">提交</el-button>
+            </template>
+    </el-dialog>
+</div>
+</template>
+
+
+<script lang="ts" setup>
+  import { ref, reactive, onMounted, nextTick, watch } from 'vue';
+  import { useRouter, useRoute } from 'vue-router';
+  import { ElMessage } from 'element-plus';
+  import { getAllDepartments } from '@/api/auth/dept';
+  import { formatDeptTree } from '@/views/disaster/utils/formatDeptTree';
+  import {
+    areaCheckListQueryDetail,
+    areaCheckListUpdateArea,
+    queryAvailableUserList,
+    areaCheckListApprove
+  } from '@/api/production-safety/responsibility-implementation';
+
+  const router = useRouter();
+  const route = useRoute();
+  const formRef = ref<any>(null);
+  const submiting = ref(false);
+  const props = defineProps({
+    visible: {
+        type: Boolean,
+        default: false
+    },
+    params: {
+        type:Object,
+        default: {
+          id: '',
+          approveType: ''
+        }
+    }
+  })
+
+  const changedDialogState = ref(false)
+  const emit = defineEmits(['confirm', 'cancel'])
+
+  const userOptions = ref<any[]>([]);
+  const safetyCenterManagerOptions = ref<any[]>([]);
+  const firstLevelDepts = ref<any[]>([]);
+  const safetyDepartmentManagerOptions = ref<any[]>([]);
+  const cascaderRef = ref({});
+  const cascaderProp = { expandTrigger: 'click', checkStrictly: true, value: 'id', label: 'deptName' };
+  watch(()=>props.visible,(newValue)=>{
+    changedDialogState.value = newValue
+  })
+  const formValue = reactive({
+    id: props.params.id,
+    buildingNo: '',
+    buildingArea: '',
+    floorRoomNo: '',
+    nameFunction: '',
+    safetyResponsibleCenter: '',
+    safetyResponsibleCenterId: [],
+    safetyCenterManager: null as number | null,
+    safetyCenterManagerName: '',
+    safetyResponsibleDepartment: '',
+    safetyResponsibleDepartmentId: [],
+    safetyDepartmentManager: null as number | null,
+    safetyDepartmentManagerName: '',
+    safetySpecificPerson: null as number | null,
+    safetySpecificPersonName: '',
+    safetyPersonContact: '',
+  });
+
+  const rules = reactive({
+    buildingArea: [{ required: true, message: '请输入楼宇/区域' }],
+    floorRoomNo: [{ required: true, message: '请输入楼层/房号' }],
+    nameFunction: [{ required: true, message: '请输入名称/功能' }],
+    safetyResponsibleCenter: [{ required: true, message: '请选择安全责任所/中心', trigger: 'change'}],
+    safetyCenterManager: [{ required: true, message: '请选择负责人', trigger: 'change' }],
+    safetyResponsibleDepartment: [{ required: true, message: '请选择安全责任部门', trigger: 'change' }],
+    safetyDepartmentManager: [{ required: true, message: '请选择负责人', trigger: 'change' }],
+    safetySpecificPerson: [{ required: true, message: '请选择安全具体责任人', trigger: 'change' }],
+    safetyPersonContact: [
+      { required: true, message: '请输入联系方式' },
+      { pattern: /^1[3-9]\d{9}$/, message: '格式不正确' },
+    ],
+  });
+
+  const cancel = ()=>{
+    submiting.value = false;
+    emit('cancel', false)
+  }
+  const getDeptData = () => {
+    getAllDepartments().then((res) => {
+      firstLevelDepts.value = formatDeptTree(res);
+    });
+  };
+
+  const getUserData = (optionList, deptName) => {
+    console.log('deptName', deptName)
+    return queryAvailableUserList({
+      pageNumber: 1,
+      pageSize: 2000,
+      queryParam: { deptName },
+    }).then((res: any) => {
+      optionList.value = (res.records || []).map((u: any) => ({
+        value: u.id,
+        label: u.realname,
+        mobile: u.mobile,
+      }));
+    });
+  };
+
+  const handleChangeDept = (val, prop) => {
+    const cascader = cascaderRef.value?.[prop];
+    const deptInfo = cascader?.getCheckedNodes();
+    if (deptInfo?.length) {
+      formValue[prop] = deptInfo[0]?.label;
+      handleQueryAvailableUserList(deptInfo[0]?.label, prop);
+    }
+  };
+
+  const handleQueryAvailableUserList = (value, prop) => {
+    if (prop === 'safetyResponsibleCenter') {
+      formValue.safetyCenterManager = null;
+      getUserData(safetyCenterManagerOptions, value);
+    } else if(prop === 'safetyResponsibleDepartment'){
+      formValue.safetyDepartmentManager = null;
+      getUserData(safetyDepartmentManagerOptions, value);
+    } else {
+    //   formValue.safetySpecificPerson = null;
+      formValue.safetyDepartmentManager = null;
+      getUserData(userOptions, value);
+    }
+  };
+
+  const syncUserName = (optionList, id, nameField) => {
+    const user = optionList.find((u) => u.value === id);
+    if (user) {
+      formValue[nameField] = user.label;
+      if (nameField === 'safetySpecificPersonName') formValue.safetyPersonContact = user.mobile;
+    }
+  };
+
+  const handlAreaCheckListQueryDetail = async () => {
+    const id = props.params.id;
+    if (!id) return;
+
+    try {
+      const res: any = await areaCheckListQueryDetail({ id });
+      if (res) {
+        // 1. 基础赋值
+        Object.assign(formValue, res);
+
+        // 2. 解析 JSON 字符串格式的 ID 数组
+        try {
+          if (typeof res.safetyResponsibleCenterId === 'string') {
+            formValue.safetyResponsibleCenterId = [] //JSON.parse(res.safetyResponsibleCenterId);
+          }
+          if (typeof res.safetyResponsibleDepartmentId === 'string') {
+            formValue.safetyResponsibleDepartmentId =  [] //JSON.parse(res.safetyResponsibleDepartmentId);
+          }
+        } catch (e) {
+          console.error('ID数组解析失败', e);
+        }
+
+        // 3. ID 类型纠正 (String to Number)
+        formValue.safetyCenterManager = null // res.safetyCenterManager ? Number(res.safetyCenterManager) : null;
+        formValue.safetyDepartmentManager = null //res.safetyDepartmentManager ? Number(res.safetyDepartmentManager) : null;
+        formValue.safetySpecificPerson = res.safetySpecificPerson ? Number(res.safetySpecificPerson) : null;
+
+        // 4. 立即同步加载人员列表,防止页面初次显示 ID 数字
+        // if (formValue.safetyResponsibleCenter) {
+        //   getUserData(safetyCenterManagerOptions, formValue.safetyResponsibleCenter);
+        // }
+        
+        // if (formValue.safetyResponsibleDepartment) {
+        //   getUserData(userOptions, formValue.safetyResponsibleDepartment);
+        // }
+        if(formValue.safetySpecificPerson) {
+            getUserData(userOptions, undefined);
+        }
+      }
+    } catch (err) {
+      ElMessage.error('详情获取失败');
+    }
+  };
+  const openDialog = async ()=>{
+    nextTick()
+    submiting.value = false;
+    await getDeptData();
+    await handlAreaCheckListQueryDetail();
+  }
+
+  const handleSubmit = () => {
+    formRef.value?.validate((valid) => {
+      if (valid) {
+        submiting.value = true;
+        // 提交时后端通常接受字符串形式,如果后端要数组,则直接传 formValue
+            console.log(formValue, '参数');
+            areaCheckListApprove({
+              approveType: 1,
+              refuseReason: null,
+              ...formValue,
+            }).then((res) => {
+                ElMessage.success('操作成功!');
+            }).finally(() => {
+                submiting.value = false
+                emit('confirm')
+            });
+      }
+    });
+  };
+</script>
+<style lang="scss" scoped>
+  @use '@/styles/page-main-layout.scss' as *;
+  @use '@/styles/page-details-layout.scss' as *;
+  @use '@/styles/basic-table-action.scss' as *;
+
+  .editor-container {
+    border: 1px solid #dcdfe6;
+    border-radius: 4px;
+    margin-right: 20px;
+    overflow: hidden;
+  }
+  :deep(.el-form-item){
+    width: 80%;
+  }
+</style>

+ 43 - 6
src/views/production-safety/implement-safety-duty/non-public-list-responsibilities/list.vue

@@ -204,6 +204,18 @@
                 <el-table-column label="变更原因" show-overflow-tooltip prop="changeReason" width="170" />
                 <el-table-column label="状态" prop="statusName" width="100" />
             </el-table>
+            <div class="pagination-container" v-if="changedListData.historiesRecords.totalRow > 0">
+                <el-pagination
+                    background
+                    layout="prev, pager, next, jumper,sizes, total"
+                    :current-page="queryParams.pageNumber"
+                    :page-size="queryParams.pageSize"
+                    :total="changedListData.historiesRecords.totalRow"
+                    :page-sizes="[10, 20, 50, 100]"
+                    @size-change="handleSizeChange2"
+                    @current-change="handleCurrentChange2"
+                />
+            </div>
         </div>
     </el-dialog>
   </div>
@@ -302,21 +314,39 @@
   };
   const changedVisible = ref(false)
 
+
   const changedListData = reactive({
   currentRecord:[],
-  historiesRecords:[]
+  historiesRecords: {
+    maxPageSize: 0,
+    optimizeCountQuery: true,
+    pageNumber: 1,
+    pageSize: 10,
+    records: [],
+    totalPage: 1,
+    totalRow: 1
+  }
 })
+  const fetchParams = reactive({
+    pageNumber: 1,
+    pageSize: 10,
+    queryParam: {
+        id:''
+    }
+  }) 
   const changedList = async(item)=>{
-    await fetchTableList(item.id)
+    fetchParams.queryParam.id = item.id
+    await fetchTableList()
     changedVisible.value = true
   }
-  const fetchTableList = async (id)=>{
-    let res = await queryChangedList({id})
+  const fetchTableList = async ()=>{
+    let res = await queryChangedList(fetchParams)
     if(!res){ return }
     Object.assign(changedListData, {
         currentRecord: res.currentRecord || [],
-        historiesRecords: res.historiesRecords || []
+        historiesRecords: res.historiesRecords
     })
+
   }
   const getDeptData = () => {
     getAllDepartments().then((res) => {
@@ -376,7 +406,14 @@
     queryParams.pageNumber = value;
     queryTableList();
   };
-
+  const handleSizeChange2 = (value) => {
+    fetchParams.pageSize = value;
+    fetchTableList()
+  };
+  const handleCurrentChange2 = (value) => {
+    fetchParams.pageNumber = value;
+    fetchTableList()
+  };
   const handleConfirmDeleteRow = (scope) => {
     areaCheckListDelete(scope.row.id).then(() => {
       ElMessage.success('删除成功!');

+ 328 - 0
src/views/production-safety/implement-safety-duty/public-area-responsibilities/confirmChange.vue

@@ -0,0 +1,328 @@
+<template>
+<div class='content'>
+    <el-dialog title="确认变更" width="70%" v-model="changedDialogState" @open="openDialog" @close="cancel">
+        <main class="safety-platform-container__main">
+            <el-form ref="formRef" label-width="auto" :model="formValue" :rules="rules">
+                <el-form-item label="楼宇/区域" prop="buildingArea">
+                <el-input v-model="formValue.buildingArea" size="large" disabled placeholder="请输入楼宇/区域" />
+                </el-form-item>
+                <el-form-item label="楼层/房号" prop="floorRoomNo">
+                <el-input v-model="formValue.floorRoomNo" size="large" disabled placeholder="请输入楼层/房号" />
+                </el-form-item>
+                <el-form-item label="名称/功能" prop="nameFunction">
+                <el-input v-model="formValue.nameFunction" size="large" disabled placeholder="请输入名称/功能"  />
+                </el-form-item>
+
+                <el-form-item label="安全责任所/中心" prop="safetyResponsibleCenter">
+                <el-cascader
+                    v-model="formValue.safetyResponsibleCenterId"
+                    size="large"
+                    style="width:100%"
+                    :ref="(el) => (cascaderRef['safetyResponsibleCenter'] = el)"
+                    :options="firstLevelDepts"
+                    :props="cascaderProp"
+                    :show-all-levels="false"
+                    placeholder="请选择安全责任所/中心"
+                    filterable
+                    clearable
+                    @change="(val) => handleChangeDept(val, 'safetyResponsibleCenter')"
+                />
+                </el-form-item>
+
+                <el-form-item label="安全责任所/中心负责人" prop="safetyCenterManager">
+                <el-select
+                    v-model="formValue.safetyCenterManager"
+                    placeholder="请选择安全责任所/中心负责人"
+                    size="large"
+                    filterable
+                    style="width:100%"
+                    @change="(val) => syncUserName(safetyCenterManagerOptions, val, 'safetyCenterManagerName')"
+                >
+                    <el-option
+                    v-for="item in safetyCenterManagerOptions"
+                    :key="item.value"
+                    :label="item.label"
+                    :value="item.value"
+                    />
+                </el-select>
+                </el-form-item>
+
+                <el-form-item label="安全责任部门" prop="safetyResponsibleDepartment">
+                <el-cascader
+                    v-model="formValue.safetyResponsibleDepartmentId"
+                    size="large"
+                    :ref="(el) => (cascaderRef['safetyResponsibleDepartment'] = el)"
+                    :options="firstLevelDepts"
+                    :props="cascaderProp"
+                    :show-all-levels="false"
+                    placeholder="请选择安全责任部门"
+                    filterable
+                    clearable
+                    style="width:100%"
+                    @change="(val) => handleChangeDept(val, 'safetyResponsibleDepartment')"
+                />
+                </el-form-item>
+
+                <el-form-item label="安全责任部门负责人" prop="safetyDepartmentManager">
+                <el-select
+                    v-model="formValue.safetyDepartmentManager"
+                    placeholder="请选择安全责任部门负责人"
+                    size="large"
+                    filterable
+                    style="width:100%"
+                    @change="(val) => syncUserName(safetyDepartmentManagerOptions, val, 'safetyDepartmentManagerName')">
+                    <el-option v-for="item in safetyDepartmentManagerOptions" :key="item.value" :label="item.label" :value="item.value" />
+                </el-select>
+                </el-form-item>
+
+                <el-form-item label="安全具体责任人" prop="safetySpecificPerson">
+                <el-select
+                    v-model="formValue.safetySpecificPerson"
+                    placeholder="请选择安全具体责任人"
+                    size="large"
+                    disabled
+                    filterable
+                    style="width:100%"
+                    @change="(val) => syncUserName(userOptions, val, 'safetySpecificPersonName')"
+                >
+                    <el-option v-for="item in userOptions" :key="item.value" :label="item.label" :value="item.value" />
+                </el-select>
+                </el-form-item>
+
+                <el-form-item label="安全具体责任人联系方式" prop="safetyPersonContact">
+                <el-input
+                    v-model="formValue.safetyPersonContact"
+                    size="large"
+                    disabled
+                    placeholder="选择安全具体责任人联系方式"
+                />
+                </el-form-item>
+            </el-form>
+            </main>
+            <template #footer>
+                <el-button @click="cancel">返回</el-button>
+                <el-button type="primary" :loading="submiting" @click="handleSubmit">提交</el-button>
+            </template>
+    </el-dialog>
+</div>
+</template>
+
+
+<script lang="ts" setup>
+  import { ref, reactive, onMounted, nextTick, watch } from 'vue';
+  import { useRouter, useRoute } from 'vue-router';
+  import { ElMessage } from 'element-plus';
+  import { getAllDepartments } from '@/api/auth/dept';
+  import { formatDeptTree } from '@/views/disaster/utils/formatDeptTree';
+  import {
+    areaCheckListQueryDetail,
+    areaCheckListUpdateArea,
+    queryAvailableUserList,
+    areaCheckListApprove
+  } from '@/api/production-safety/responsibility-implementation';
+
+  const router = useRouter();
+  const route = useRoute();
+  const formRef = ref<any>(null);
+  const submiting = ref(false);
+  const props = defineProps({
+    visible: {
+        type: Boolean,
+        default: false
+    },
+    params: {
+        type:Object,
+        default: {
+          id: '',
+          approveType: ''
+        }
+    }
+  })
+
+  const changedDialogState = ref(false)
+  const emit = defineEmits(['confirm', 'cancel'])
+
+  const userOptions = ref<any[]>([]);
+  const safetyCenterManagerOptions = ref<any[]>([]);
+  const firstLevelDepts = ref<any[]>([]);
+  const safetyDepartmentManagerOptions = ref<any[]>([]);
+  const cascaderRef = ref({});
+  const cascaderProp = { expandTrigger: 'click', checkStrictly: true, value: 'id', label: 'deptName' };
+  watch(()=>props.visible,(newValue)=>{
+    changedDialogState.value = newValue
+  })
+  const formValue = reactive({
+    id: props.params.id,
+    buildingNo: '',
+    buildingArea: '',
+    floorRoomNo: '',
+    nameFunction: '',
+    safetyResponsibleCenter: '',
+    safetyResponsibleCenterId: [],
+    safetyCenterManager: null as number | null,
+    safetyCenterManagerName: '',
+    safetyResponsibleDepartment: '',
+    safetyResponsibleDepartmentId: [],
+    safetyDepartmentManager: null as number | null,
+    safetyDepartmentManagerName: '',
+    safetySpecificPerson: null as number | null,
+    safetySpecificPersonName: '',
+    safetyPersonContact: '',
+  });
+
+  const rules = reactive({
+    buildingArea: [{ required: true, message: '请输入楼宇/区域' }],
+    floorRoomNo: [{ required: true, message: '请输入楼层/房号' }],
+    nameFunction: [{ required: true, message: '请输入名称/功能' }],
+    safetyResponsibleCenter: [{ required: true, message: '请选择安全责任所/中心', trigger: 'change'}],
+    safetyCenterManager: [{ required: true, message: '请选择负责人', trigger: 'change' }],
+    safetyResponsibleDepartment: [{ required: true, message: '请选择安全责任部门', trigger: 'change' }],
+    safetyDepartmentManager: [{ required: true, message: '请选择负责人', trigger: 'change' }],
+    safetySpecificPerson: [{ required: true, message: '请选择安全具体责任人', trigger: 'change' }],
+    safetyPersonContact: [
+      { required: true, message: '请输入联系方式' },
+      { pattern: /^1[3-9]\d{9}$/, message: '格式不正确' },
+    ],
+  });
+
+  const cancel = ()=>{
+    submiting.value = false;
+    emit('cancel', false)
+  }
+  const getDeptData = () => {
+    getAllDepartments().then((res) => {
+      firstLevelDepts.value = formatDeptTree(res);
+    });
+  };
+
+  const getUserData = (optionList, deptName) => {
+    console.log('deptName', deptName)
+    return queryAvailableUserList({
+      pageNumber: 1,
+      pageSize: 2000,
+      queryParam: { deptName },
+    }).then((res: any) => {
+      optionList.value = (res.records || []).map((u: any) => ({
+        value: u.id,
+        label: u.realname,
+        mobile: u.mobile,
+      }));
+    });
+  };
+
+  const handleChangeDept = (val, prop) => {
+    const cascader = cascaderRef.value?.[prop];
+    const deptInfo = cascader?.getCheckedNodes();
+    if (deptInfo?.length) {
+      formValue[prop] = deptInfo[0]?.label;
+      handleQueryAvailableUserList(deptInfo[0]?.label, prop);
+    }
+  };
+
+  const handleQueryAvailableUserList = (value, prop) => {
+    if (prop === 'safetyResponsibleCenter') {
+      formValue.safetyCenterManager = null;
+      getUserData(safetyCenterManagerOptions, value);
+    } else if(prop === 'safetyResponsibleDepartment'){
+      formValue.safetyDepartmentManager = null;
+      getUserData(safetyDepartmentManagerOptions, value);
+    } else {
+    //   formValue.safetySpecificPerson = null;
+      formValue.safetyDepartmentManager = null;
+      getUserData(userOptions, value);
+    }
+  };
+
+  const syncUserName = (optionList, id, nameField) => {
+    const user = optionList.find((u) => u.value === id);
+    if (user) {
+      formValue[nameField] = user.label;
+      if (nameField === 'safetySpecificPersonName') formValue.safetyPersonContact = user.mobile;
+    }
+  };
+
+  const handlAreaCheckListQueryDetail = async () => {
+    const id = props.params.id;
+    if (!id) return;
+
+    try {
+      const res: any = await areaCheckListQueryDetail({ id });
+      if (res) {
+        // 1. 基础赋值
+        Object.assign(formValue, res);
+
+        // 2. 解析 JSON 字符串格式的 ID 数组
+        try {
+          if (typeof res.safetyResponsibleCenterId === 'string') {
+            formValue.safetyResponsibleCenterId = [] //JSON.parse(res.safetyResponsibleCenterId);
+          }
+          if (typeof res.safetyResponsibleDepartmentId === 'string') {
+            formValue.safetyResponsibleDepartmentId =  [] //JSON.parse(res.safetyResponsibleDepartmentId);
+          }
+        } catch (e) {
+          console.error('ID数组解析失败', e);
+        }
+
+        // 3. ID 类型纠正 (String to Number)
+        formValue.safetyCenterManager = null // res.safetyCenterManager ? Number(res.safetyCenterManager) : null;
+        formValue.safetyDepartmentManager = null //res.safetyDepartmentManager ? Number(res.safetyDepartmentManager) : null;
+        formValue.safetySpecificPerson = res.safetySpecificPerson ? Number(res.safetySpecificPerson) : null;
+
+        // 4. 立即同步加载人员列表,防止页面初次显示 ID 数字
+        // if (formValue.safetyResponsibleCenter) {
+        //   getUserData(safetyCenterManagerOptions, formValue.safetyResponsibleCenter);
+        // }
+        
+        // if (formValue.safetyResponsibleDepartment) {
+        //   getUserData(userOptions, formValue.safetyResponsibleDepartment);
+        // }
+        if(formValue.safetySpecificPerson) {
+            getUserData(userOptions, undefined);
+        }
+      }
+    } catch (err) {
+      ElMessage.error('详情获取失败');
+    }
+  };
+  const openDialog = async ()=>{
+    nextTick()
+    submiting.value = false;
+    await getDeptData();
+    await handlAreaCheckListQueryDetail();
+  }
+
+  const handleSubmit = () => {
+    formRef.value?.validate((valid) => {
+      if (valid) {
+        submiting.value = true;
+        // 提交时后端通常接受字符串形式,如果后端要数组,则直接传 formValue
+            console.log(formValue, '参数');
+            areaCheckListApprove({
+              approveType: 1,
+              refuseReason: null,
+              ...formValue,
+            }).then((res) => {
+                ElMessage.success('操作成功!');
+            }).finally(() => {
+                submiting.value = false
+                emit('confirm')
+            });
+      }
+    });
+  };
+</script>
+<style lang="scss" scoped>
+  @use '@/styles/page-main-layout.scss' as *;
+  @use '@/styles/page-details-layout.scss' as *;
+  @use '@/styles/basic-table-action.scss' as *;
+
+  .editor-container {
+    border: 1px solid #dcdfe6;
+    border-radius: 4px;
+    margin-right: 20px;
+    overflow: hidden;
+  }
+  :deep(.el-form-item){
+    width: 80%;
+  }
+</style>

+ 69 - 14
src/views/production-safety/implement-safety-duty/public-area-responsibilities/list.vue

@@ -166,7 +166,7 @@
         </div>
         <div class="table-content">
             <h4>历史记录(变更前)</h4>
-            <el-table :data="changedListData.historiesRecords">
+            <el-table :data="changedListData.historiesRecords.records">
                 <el-table-column type="index" label="编号" width="80" />
                 <el-table-column label="变更时间" prop="createdAt" width="180" />
                 <el-table-column label="变更人" prop="safetySpecificPersonName" width="180" />
@@ -182,8 +182,22 @@
                 <el-table-column label="变更原因" show-overflow-tooltip prop="changeReason" width="170" />
                 <el-table-column label="状态" prop="statusName" width="100" />
             </el-table>
+            <div class="pagination-container" v-if="changedListData.historiesRecords.totalRow > 0">
+                <el-pagination
+                    background
+                    layout="prev, pager, next, jumper,sizes, total"
+                    :current-page="queryParams.pageNumber"
+                    :page-size="queryParams.pageSize"
+                    :total="changedListData.historiesRecords.totalRow"
+                    :page-sizes="[10, 20, 50, 100]"
+                    @size-change="handleSizeChange2"
+                    @current-change="handleCurrentChange2"
+                />
+            </div>
         </div>
     </el-dialog>
+    <!-- 确认弹窗 -->
+    <confirmChange :visible="changedDialogState" :params="changedParams" @confirm="handleConfirmChange" @cancel="handleCancelChange" />
   </div>
   <BatchImport
     :visible="batchImportVisible"
@@ -199,6 +213,7 @@
   import { onMounted, ref, reactive } from 'vue';
   import { ElMessage } from 'element-plus';
   import { useRouter } from 'vue-router';
+  import confirmChange from './confirmChange.vue';
   import {
     areaCheckListQueryPage,
     areaCheckListApprove,
@@ -230,6 +245,7 @@
     },
   });
 
+
   // 批量导入
   const batchImportVisible = ref(false);
   const { urlPrefix } = useGlobSetting();
@@ -243,20 +259,37 @@
   const changedVisible = ref(false)
   const changedListData = reactive({
   currentRecord:[],
-  historiesRecords:[]
+  historiesRecords: {
+    maxPageSize: 0,
+    optimizeCountQuery: true,
+    pageNumber: 1,
+    pageSize: 10,
+    records: [],
+    totalPage: 1,
+    totalRow: 1
+  }
 })
+  const fetchParams = reactive({
+    pageNumber: 1,
+    pageSize: 10,
+    queryParam: {
+        id:''
+    }
+  }) 
   const changedList = async(item)=>{
-    await fetchTableList(item.id)
+    fetchParams.queryParam.id = item.id
+    await fetchTableList()
     changedVisible.value = true
   }
-  const fetchTableList = async (id)=>{
-    let res = await queryChangedList({id})
+  const fetchTableList = async ()=>{
+    let res = await queryChangedList(fetchParams)
     if(!res){ return }
     Object.assign(changedListData, {
         currentRecord: res.currentRecord || [],
-        historiesRecords: res.historiesRecords || []
+        historiesRecords: res.historiesRecords
     })
   }
+  
   const tableData = reactive({
     data: [],
     total: 0,
@@ -286,30 +319,52 @@
       console.log(e);
     }
   }
-
+  const changedDialogState = ref(false)
+  
+  const changedParams = reactive({})
+  // 弹出弹窗,修改必填项
   const handleAreaCheckListApprove = (scope, approveType) => {
+    if(approveType===1){
+        changedDialogState.value = true
+        Object.assign(changedParams, {
+            id: scope.row.id,
+            approveType
+        })
+        return 
+    }
     areaCheckListApprove({
       id: scope.row.id,
       approveType,
       refuseReason: null,
     }).then((res) => {
-      if (approveType === 1) {
-        ElMessage.success('请尽快修改该责任清单的安全责任所/中心、安全责任部门及相关负责人信息');
-      } else {
-        ElMessage.success('操作成功!');
-      }
+      ElMessage.success('操作成功!');
       queryTableList();
     });
   };
-
+  // 确认回调
+  const handleConfirmChange = ()=>{
+    changedDialogState.value = false
+  }
+  const handleCancelChange = ()=>{
+    changedDialogState.value = false
+  }
   const handleSizeChange = (value) => {
     queryParams.pageSize = value;
     queryTableList();
   };
-  const handleCurrentChange = (value) => {
+   const handleCurrentChange = (value) => {
     queryParams.pageNumber = value;
     queryTableList();
   };
+  const handleSizeChange2 = (value) => {
+    fetchParams.pageSize = value;
+    fetchTableList()
+  };
+  const handleCurrentChange2 = (value) => {
+    fetchParams.pageNumber = value;
+    fetchTableList()
+  };
+ 
 
   const handleConfirmDeleteRow = (scope) => {
     areaCheckListDelete(scope.row.id).then(() => {

+ 328 - 0
src/views/production-safety/implement-safety-duty/public-list-responsibilities/confirmChange.vue

@@ -0,0 +1,328 @@
+<template>
+<div class='content'>
+    <el-dialog title="确认变更" width="70%" v-model="changedDialogState" @open="openDialog" @close="cancel">
+        <main class="safety-platform-container__main">
+            <el-form ref="formRef" label-width="auto" :model="formValue" :rules="rules">
+                <el-form-item label="楼宇/区域" prop="buildingArea">
+                <el-input v-model="formValue.buildingArea" size="large" disabled placeholder="请输入楼宇/区域" />
+                </el-form-item>
+                <el-form-item label="楼层/房号" prop="floorRoomNo">
+                <el-input v-model="formValue.floorRoomNo" size="large" disabled placeholder="请输入楼层/房号" />
+                </el-form-item>
+                <el-form-item label="名称/功能" prop="nameFunction">
+                <el-input v-model="formValue.nameFunction" size="large" disabled placeholder="请输入名称/功能"  />
+                </el-form-item>
+
+                <el-form-item label="安全责任所/中心" prop="safetyResponsibleCenter">
+                <el-cascader
+                    v-model="formValue.safetyResponsibleCenterId"
+                    size="large"
+                    style="width:100%"
+                    :ref="(el) => (cascaderRef['safetyResponsibleCenter'] = el)"
+                    :options="firstLevelDepts"
+                    :props="cascaderProp"
+                    :show-all-levels="false"
+                    placeholder="请选择安全责任所/中心"
+                    filterable
+                    clearable
+                    @change="(val) => handleChangeDept(val, 'safetyResponsibleCenter')"
+                />
+                </el-form-item>
+
+                <el-form-item label="安全责任所/中心负责人" prop="safetyCenterManager">
+                <el-select
+                    v-model="formValue.safetyCenterManager"
+                    placeholder="请选择安全责任所/中心负责人"
+                    size="large"
+                    filterable
+                    style="width:100%"
+                    @change="(val) => syncUserName(safetyCenterManagerOptions, val, 'safetyCenterManagerName')"
+                >
+                    <el-option
+                    v-for="item in safetyCenterManagerOptions"
+                    :key="item.value"
+                    :label="item.label"
+                    :value="item.value"
+                    />
+                </el-select>
+                </el-form-item>
+
+                <el-form-item label="安全责任部门" prop="safetyResponsibleDepartment">
+                <el-cascader
+                    v-model="formValue.safetyResponsibleDepartmentId"
+                    size="large"
+                    :ref="(el) => (cascaderRef['safetyResponsibleDepartment'] = el)"
+                    :options="firstLevelDepts"
+                    :props="cascaderProp"
+                    :show-all-levels="false"
+                    placeholder="请选择安全责任部门"
+                    filterable
+                    clearable
+                    style="width:100%"
+                    @change="(val) => handleChangeDept(val, 'safetyResponsibleDepartment')"
+                />
+                </el-form-item>
+
+                <el-form-item label="安全责任部门负责人" prop="safetyDepartmentManager">
+                <el-select
+                    v-model="formValue.safetyDepartmentManager"
+                    placeholder="请选择安全责任部门负责人"
+                    size="large"
+                    filterable
+                    style="width:100%"
+                    @change="(val) => syncUserName(safetyDepartmentManagerOptions, val, 'safetyDepartmentManagerName')">
+                    <el-option v-for="item in safetyDepartmentManagerOptions" :key="item.value" :label="item.label" :value="item.value" />
+                </el-select>
+                </el-form-item>
+
+                <el-form-item label="安全具体责任人" prop="safetySpecificPerson">
+                <el-select
+                    v-model="formValue.safetySpecificPerson"
+                    placeholder="请选择安全具体责任人"
+                    size="large"
+                    disabled
+                    filterable
+                    style="width:100%"
+                    @change="(val) => syncUserName(userOptions, val, 'safetySpecificPersonName')"
+                >
+                    <el-option v-for="item in userOptions" :key="item.value" :label="item.label" :value="item.value" />
+                </el-select>
+                </el-form-item>
+
+                <el-form-item label="安全具体责任人联系方式" prop="safetyPersonContact">
+                <el-input
+                    v-model="formValue.safetyPersonContact"
+                    size="large"
+                    disabled
+                    placeholder="选择安全具体责任人联系方式"
+                />
+                </el-form-item>
+            </el-form>
+            </main>
+            <template #footer>
+                <el-button @click="cancel">返回</el-button>
+                <el-button type="primary" :loading="submiting" @click="handleSubmit">提交</el-button>
+            </template>
+    </el-dialog>
+</div>
+</template>
+
+
+<script lang="ts" setup>
+  import { ref, reactive, onMounted, nextTick, watch } from 'vue';
+  import { useRouter, useRoute } from 'vue-router';
+  import { ElMessage } from 'element-plus';
+  import { getAllDepartments } from '@/api/auth/dept';
+  import { formatDeptTree } from '@/views/disaster/utils/formatDeptTree';
+  import {
+    areaCheckListQueryDetail,
+    areaCheckListUpdateArea,
+    queryAvailableUserList,
+    areaCheckListApprove
+  } from '@/api/production-safety/responsibility-implementation';
+
+  const router = useRouter();
+  const route = useRoute();
+  const formRef = ref<any>(null);
+  const submiting = ref(false);
+  const props = defineProps({
+    visible: {
+        type: Boolean,
+        default: false
+    },
+    params: {
+        type:Object,
+        default: {
+          id: '',
+          approveType: ''
+        }
+    }
+  })
+
+  const changedDialogState = ref(false)
+  const emit = defineEmits(['confirm', 'cancel'])
+
+  const userOptions = ref<any[]>([]);
+  const safetyCenterManagerOptions = ref<any[]>([]);
+  const firstLevelDepts = ref<any[]>([]);
+  const safetyDepartmentManagerOptions = ref<any[]>([]);
+  const cascaderRef = ref({});
+  const cascaderProp = { expandTrigger: 'click', checkStrictly: true, value: 'id', label: 'deptName' };
+  watch(()=>props.visible,(newValue)=>{
+    changedDialogState.value = newValue
+  })
+  const formValue = reactive({
+    id: props.params.id,
+    buildingNo: '',
+    buildingArea: '',
+    floorRoomNo: '',
+    nameFunction: '',
+    safetyResponsibleCenter: '',
+    safetyResponsibleCenterId: [],
+    safetyCenterManager: null as number | null,
+    safetyCenterManagerName: '',
+    safetyResponsibleDepartment: '',
+    safetyResponsibleDepartmentId: [],
+    safetyDepartmentManager: null as number | null,
+    safetyDepartmentManagerName: '',
+    safetySpecificPerson: null as number | null,
+    safetySpecificPersonName: '',
+    safetyPersonContact: '',
+  });
+
+  const rules = reactive({
+    buildingArea: [{ required: true, message: '请输入楼宇/区域' }],
+    floorRoomNo: [{ required: true, message: '请输入楼层/房号' }],
+    nameFunction: [{ required: true, message: '请输入名称/功能' }],
+    safetyResponsibleCenter: [{ required: true, message: '请选择安全责任所/中心', trigger: 'change'}],
+    safetyCenterManager: [{ required: true, message: '请选择负责人', trigger: 'change' }],
+    safetyResponsibleDepartment: [{ required: true, message: '请选择安全责任部门', trigger: 'change' }],
+    safetyDepartmentManager: [{ required: true, message: '请选择负责人', trigger: 'change' }],
+    safetySpecificPerson: [{ required: true, message: '请选择安全具体责任人', trigger: 'change' }],
+    safetyPersonContact: [
+      { required: true, message: '请输入联系方式' },
+      { pattern: /^1[3-9]\d{9}$/, message: '格式不正确' },
+    ],
+  });
+
+  const cancel = ()=>{
+    submiting.value = false;
+    emit('cancel', false)
+  }
+  const getDeptData = () => {
+    getAllDepartments().then((res) => {
+      firstLevelDepts.value = formatDeptTree(res);
+    });
+  };
+
+  const getUserData = (optionList, deptName) => {
+    console.log('deptName', deptName)
+    return queryAvailableUserList({
+      pageNumber: 1,
+      pageSize: 2000,
+      queryParam: { deptName },
+    }).then((res: any) => {
+      optionList.value = (res.records || []).map((u: any) => ({
+        value: u.id,
+        label: u.realname,
+        mobile: u.mobile,
+      }));
+    });
+  };
+
+  const handleChangeDept = (val, prop) => {
+    const cascader = cascaderRef.value?.[prop];
+    const deptInfo = cascader?.getCheckedNodes();
+    if (deptInfo?.length) {
+      formValue[prop] = deptInfo[0]?.label;
+      handleQueryAvailableUserList(deptInfo[0]?.label, prop);
+    }
+  };
+
+  const handleQueryAvailableUserList = (value, prop) => {
+    if (prop === 'safetyResponsibleCenter') {
+      formValue.safetyCenterManager = null;
+      getUserData(safetyCenterManagerOptions, value);
+    } else if(prop === 'safetyResponsibleDepartment'){
+      formValue.safetyDepartmentManager = null;
+      getUserData(safetyDepartmentManagerOptions, value);
+    } else {
+    //   formValue.safetySpecificPerson = null;
+      formValue.safetyDepartmentManager = null;
+      getUserData(userOptions, value);
+    }
+  };
+
+  const syncUserName = (optionList, id, nameField) => {
+    const user = optionList.find((u) => u.value === id);
+    if (user) {
+      formValue[nameField] = user.label;
+      if (nameField === 'safetySpecificPersonName') formValue.safetyPersonContact = user.mobile;
+    }
+  };
+
+  const handlAreaCheckListQueryDetail = async () => {
+    const id = props.params.id;
+    if (!id) return;
+
+    try {
+      const res: any = await areaCheckListQueryDetail({ id });
+      if (res) {
+        // 1. 基础赋值
+        Object.assign(formValue, res);
+
+        // 2. 解析 JSON 字符串格式的 ID 数组
+        try {
+          if (typeof res.safetyResponsibleCenterId === 'string') {
+            formValue.safetyResponsibleCenterId = [] //JSON.parse(res.safetyResponsibleCenterId);
+          }
+          if (typeof res.safetyResponsibleDepartmentId === 'string') {
+            formValue.safetyResponsibleDepartmentId =  [] //JSON.parse(res.safetyResponsibleDepartmentId);
+          }
+        } catch (e) {
+          console.error('ID数组解析失败', e);
+        }
+
+        // 3. ID 类型纠正 (String to Number)
+        formValue.safetyCenterManager = null // res.safetyCenterManager ? Number(res.safetyCenterManager) : null;
+        formValue.safetyDepartmentManager = null //res.safetyDepartmentManager ? Number(res.safetyDepartmentManager) : null;
+        formValue.safetySpecificPerson = res.safetySpecificPerson ? Number(res.safetySpecificPerson) : null;
+
+        // 4. 立即同步加载人员列表,防止页面初次显示 ID 数字
+        // if (formValue.safetyResponsibleCenter) {
+        //   getUserData(safetyCenterManagerOptions, formValue.safetyResponsibleCenter);
+        // }
+        
+        // if (formValue.safetyResponsibleDepartment) {
+        //   getUserData(userOptions, formValue.safetyResponsibleDepartment);
+        // }
+        if(formValue.safetySpecificPerson) {
+            getUserData(userOptions, undefined);
+        }
+      }
+    } catch (err) {
+      ElMessage.error('详情获取失败');
+    }
+  };
+  const openDialog = async ()=>{
+    nextTick()
+    submiting.value = false;
+    await getDeptData();
+    await handlAreaCheckListQueryDetail();
+  }
+
+  const handleSubmit = () => {
+    formRef.value?.validate((valid) => {
+      if (valid) {
+        submiting.value = true;
+        // 提交时后端通常接受字符串形式,如果后端要数组,则直接传 formValue
+            console.log(formValue, '参数');
+            areaCheckListApprove({
+              approveType: 1,
+              refuseReason: null,
+              ...formValue,
+            }).then((res) => {
+                ElMessage.success('操作成功!');
+            }).finally(() => {
+                submiting.value = false
+                emit('confirm')
+            });
+      }
+    });
+  };
+</script>
+<style lang="scss" scoped>
+  @use '@/styles/page-main-layout.scss' as *;
+  @use '@/styles/page-details-layout.scss' as *;
+  @use '@/styles/basic-table-action.scss' as *;
+
+  .editor-container {
+    border: 1px solid #dcdfe6;
+    border-radius: 4px;
+    margin-right: 20px;
+    overflow: hidden;
+  }
+  :deep(.el-form-item){
+    width: 80%;
+  }
+</style>

+ 65 - 13
src/views/production-safety/implement-safety-duty/public-list-responsibilities/list.vue

@@ -199,8 +199,22 @@
                 <el-table-column label="变更原因" show-overflow-tooltip prop="changeReason" width="170" />
                 <el-table-column label="状态" prop="statusName" width="100" />
             </el-table>
+            <div class="pagination-container" v-if="changedListData.historiesRecords.totalRow > 0">
+                <el-pagination
+                    background
+                    layout="prev, pager, next, jumper,sizes, total"
+                    :current-page="queryParams.pageNumber"
+                    :page-size="queryParams.pageSize"
+                    :total="changedListData.historiesRecords.totalRow"
+                    :page-sizes="[10, 20, 50, 100]"
+                    @size-change="handleSizeChange2"
+                    @current-change="handleCurrentChange2"
+                />
+            </div>
         </div>
     </el-dialog>
+    <!-- 确认弹窗 -->
+    <confirmChange :visible="changedDialogState" :params="changedParams" @confirm="handleConfirmChange" @cancel="handleCancelChange" />
   </div>
   <BatchImport
     :visible="batchImportVisible"
@@ -287,19 +301,36 @@
 
   const changedListData = reactive({
   currentRecord:[],
-  historiesRecords:[]
+  historiesRecords: {
+    maxPageSize: 0,
+    optimizeCountQuery: true,
+    pageNumber: 1,
+    pageSize: 10,
+    records: [],
+    totalPage: 1,
+    totalRow: 1
+  }
 })
+  const fetchParams = reactive({
+    pageNumber: 1,
+    pageSize: 10,
+    queryParam: {
+        id:''
+    }
+  }) 
   const changedList = async(item)=>{
-    await fetchTableList(item.id)
+    fetchParams.queryParam.id = item.id
+    await fetchTableList()
     changedVisible.value = true
   }
-  const fetchTableList = async (id)=>{
-    let res = await queryChangedList({id})
+  const fetchTableList = async ()=>{
+    let res = await queryChangedList(fetchParams)
     if(!res){ return }
     Object.assign(changedListData, {
         currentRecord: res.currentRecord || [],
-        historiesRecords: res.historiesRecords || []
+        historiesRecords: res.historiesRecords
     })
+
   }
   const handleTabChange = (tab) => {
     if (tab === 1) {
@@ -342,22 +373,35 @@
       }));
     });
   };
-
+  const changedDialogState = ref(false)
+  
+  const changedParams = reactive({})
+  // 弹出弹窗,修改必填项
   const handleAreaCheckListApprove = (scope, approveType) => {
+    if(approveType===1){
+        changedDialogState.value = true
+        Object.assign(changedParams, {
+            id: scope.row.id,
+            approveType
+        })
+        return 
+    }
     areaCheckListApprove({
       id: scope.row.id,
       approveType,
       refuseReason: null,
-    }).then(() => {
-      if (approveType === 1) {
-        ElMessage.success('请尽快修改该责任清单的安全责任所/中心、安全责任部门及相关负责人信息');
-      } else {
-        ElMessage.success('操作成功!');
-      }
-
+    }).then((res) => {
+      ElMessage.success('操作成功!');
       queryTableList();
     });
   };
+  // 确认回调
+  const handleConfirmChange = ()=>{
+    changedDialogState.value = false
+  }
+  const handleCancelChange = ()=>{
+    changedDialogState.value = false
+  }
 
   const handleSizeChange = (value) => {
     queryParams.pageSize = value;
@@ -368,6 +412,14 @@
     queryTableList();
   };
 
+const handleSizeChange2 = (value) => {
+    fetchParams.pageSize = value;
+    fetchTableList()
+  };
+  const handleCurrentChange2 = (value) => {
+    fetchParams.pageNumber = value;
+    fetchTableList()
+  };
   const handleConfirmDeleteRow = (scope) => {
     areaCheckListDelete(scope.row.id).then(() => {
       ElMessage.success('删除成功!');

+ 1 - 7
src/views/production-safety/risk-identification-and-control/equipment-high-alert/configs/form.ts

@@ -2,7 +2,7 @@
  * @Author: liuJie
  * @Date: 2026-03-05 10:11:20
  * @LastEditors: liuJie
- * @LastEditTime: 2026-03-17 10:31:07
+ * @LastEditTime: 2026-03-20 16:53:34
  * @Describe: file describe
  */
 import type { FormConfig } from '@/types/basic-form';
@@ -13,12 +13,6 @@ export const DEVICE_CATEGORY_OPTIONS = [
   { label: '传感器', value: 'sensor' },
 ];
 
-export const DEVICE_TYPE = {
-    siren:'报警器',
-    sensor: '传感器'
-}
-
-
 /** 告警类型 */
 export const Alarm_TYPE_OPTIONS = [
   { label: '安全告警', value: 'safe_alarm' },

+ 12 - 8
src/views/production-safety/risk-identification-and-control/equipment-high-alert/list.vue

@@ -35,10 +35,10 @@
                   class="act-search-input"
                 >
                   <el-option
-                    v-for="opt in DEVICE_CATEGORY_OPTIONS"
-                    :key="opt.value"
-                    :label="opt.label"
-                    :value="opt.value"
+                    v-for="opt in alarmTypeData"
+                    :key="opt.id"
+                    :label="opt.name"
+                    :value="opt.code"
                   />
                 </el-select>
               </div>
@@ -190,16 +190,15 @@
   import useTableConfig from '@/hooks/useTableConfigHook';
   import ActionButton from '@/components/ActionButton.vue';
   import { TABLE_OPTIONS, SPECIAL_EQUIPMENT_TABLE_COLUMNS } from './configs/tables';
-  import { DEVICE_CATEGORY_OPTIONS, Alarm_TYPE_OPTIONS, DEVICE_TYPE, ALARM_TYPE, type DETAIL_DATA_TYPE, ALARM_STATUS, HANDLE_STATUS} from './configs/form';
-  import {type QueryParamType, equipmentHighAlertList, deptList, exportTableData, DeviceTypeList} from '@/api/equipment-high-alert-List'
+  import { DEVICE_CATEGORY_OPTIONS, Alarm_TYPE_OPTIONS, ALARM_TYPE, type DETAIL_DATA_TYPE, ALARM_STATUS, HANDLE_STATUS} from './configs/form';
+  import {type QueryParamType, equipmentHighAlertList, deptList, exportTableData, DeviceTypeList, DeviceType} from '@/api/equipment-high-alert-List'
   import { downloadByData } from '@/utils/file/download';
 
-  import dayjs from 'dayjs';
   const loading = ref(false);
   const dateRange = ref<[string, string] | null>(null);
   const DetailDialog = ref<boolean>(false)
   const detail = reactive({}) as DETAIL_DATA_TYPE
-  const alarmTypeData = ref([])
+  const alarmTypeData = ref<DeviceType[]>([])
   // BasicTable
   const basicTableRef = ref<InstanceType<typeof BasicTable>>();
   const { tableConfig, pagination } = useTableConfig(SPECIAL_EQUIPMENT_TABLE_COLUMNS, TABLE_OPTIONS);
@@ -224,6 +223,7 @@
       endTime: undefined,
     },
   });
+const DEVICE_TYPE = reactive({})
 
   // 部门树(queryAllDeptTree 样式)
   const deptOptions = ref<any[]>([]);
@@ -264,6 +264,10 @@
     let res = await DeviceTypeList()
     if(res){
         alarmTypeData.value = res
+        //  用于映射
+        res.forEach(item=>{
+            DEVICE_TYPE[item.code] = item.name;
+        })
     }
   }
   const loadDeptTree = async () => {