Parcourir la source

feat:完成安全组织体系优化

sunqijun il y a 3 semaines
Parent
commit
007ed0e584

+ 3 - 3
src/router/routers/production-safety-router/productionSafetySystem.ts

@@ -247,9 +247,9 @@ const productionSafetySystemRoutes: RouteComponent[] = [{
       path: 'security-organizational-structure',
       component: '/production-safety/productionSafetySystem/securityOrganizationalStructure/securityOrganizationalStructure',
       meta: {
-        title: '安全组织体系管理(组织员工)',
+        title: '安全组织体系管理',
         icon: 'OverviewIcon',
-        activeMenu: '/work-safety/production-safety-system/safety-organization-system-management',
+        activeMenu: '/work-safety/production-safety-system/security-organizational-structure',
         isRoot: false,
         hidden: false,
         noCache: false,
@@ -263,7 +263,7 @@ const productionSafetySystemRoutes: RouteComponent[] = [{
         component: '/production-safety/productionSafetySystem/securityOrganizationalStructure/securityOrganizationalStructureItem',
         meta: {
             title: '安全组织体系管理详情',
-            activeMenu: '/work-safety/production-safety-system/safety-organization-system-management',
+            activeMenu: '/work-safety/production-safety-system/security-organizational-structure',
             icon: 'OverviewIcon',
             isRoot: false,
             hidden: false,

+ 1 - 1
src/views/production-safety/productionSafetySystem/safetyOrganizationSystemManagement/components/TeamDetailDrawer.vue

@@ -8,7 +8,7 @@
     </div>
     <div class="team-detail__description">
       <div class="team-detail__description__title"> 队伍职责 </div>
-      <div class="team-detail__description__content"> {{ organization?.depResp }} </div>
+      <div class="team-detail__description__content"> {{ organization?.depResp || '暂无职责'}} </div>
     </div>
   </el-drawer>
 </template>

+ 8 - 1
src/views/production-safety/productionSafetySystem/safetyOrganizationSystemManagement/configs/form.ts

@@ -2,7 +2,7 @@
  * @Author: liuJie
  * @Date: 2026-01-27 16:29:28
  * @LastEditors: liuJie
- * @LastEditTime: 2026-02-06 13:35:38
+ * @LastEditTime: 2026-04-10 14:16:34
  * @Describe: file describe
  */
 import { FormConfig } from '@/types/basic-form';
@@ -68,9 +68,16 @@ export const FORM_RULES = {
     { min: 1, max: 10, message: '长度在 1 到 10 个字符', trigger: 'blur' },
   ],
   orgId: [{ required: true, message: '请选择组织名称', trigger: 'change' }],
+  jobName: [{ required: true, message: '请输入岗位名称', trigger: 'blur' }],
   jobResp: [
     { required: true, message: '请填写岗位职责', trigger: 'blur' },
     { min: 1, max: 300, message: '最大字数300字', trigger: 'blur' },
   ],
   status: [{ required: true, message: '请选择状态', trigger: 'blur' }],
 };
+
+
+export const SafetyOrgUserRules = {
+    userNum: [{ required: true, message: '请输入组织人数', trigger: 'blur' }],
+    depResp: [{ required: true, message: '请填写组织职责', trigger: 'blur' }]
+}

+ 18 - 11
src/views/production-safety/productionSafetySystem/safetyOrganizationSystemManagement/configs/tables.ts

@@ -2,7 +2,7 @@
  * @Author: liuJie
  * @Date: 2026-01-27 16:29:28
  * @LastEditors: liuJie
- * @LastEditTime: 2026-03-30 10:16:11
+ * @LastEditTime: 2026-04-10 14:16:48
  * @Describe: file describe
  */
 import type { TableColumnProps } from '@/types/basic-table';
@@ -21,15 +21,15 @@ export const TABLE_COLUMNS: TableColumnProps[] = [
     align: 'center',
     width: '80px',
   },
-  {
-    label: '员工工号',
-    prop: 'employeeId',
-    align: 'left',
+    {
+    label: '员工姓名',
+    prop: 'employeeName',
+    align: 'center',
     minWidth: '120px',
   },
   {
-    label: '员工姓名',
-    prop: 'employeeName',
+    label: '员工工号',
+    prop: 'employeeId',
     align: 'center',
     minWidth: '120px',
   },
@@ -37,20 +37,27 @@ export const TABLE_COLUMNS: TableColumnProps[] = [
     label: '状态',
     prop: 'status',
     slot: 'status',
-    align: 'left',
-    minWidth: '120px',
+    align: 'center',
+    minWidth: '90px',
   },
 
   {
     label: '组织名称',
     prop: 'orgName',
-    align: 'left',
+    align: 'center',
     minWidth: '140px',
+  },
+    {
+    label: '岗位名称',
+    prop: 'jobName',
+    align: 'center',
+    minWidth: '150px',
+    showOverflowTooltip: true,
   },
   {
     label: '岗位职责',
     prop: 'jobResp',
-    align: 'left',
+    align: 'center',
     minWidth: '150px',
     showOverflowTooltip: true,
   },

+ 365 - 201
src/views/production-safety/productionSafetySystem/safetyOrganizationSystemManagement/safetyOrganizationSystemManagement.vue

@@ -1,15 +1,16 @@
 <template>
+    <!-- 旧版本,可舍弃,暂时为了兼容测试 -->
   <div class="safety-platform-container">
     <header class="safety-platform-container__header">
       <div class="breadcrumb-title"> 安全组织体系管理 </div>
     </header>
-    <main class="safety-platform-container__main flex">
+    <main class="safety-platform-container__main flex platform-main">
       <div class="nav">
-        <el-button type="primary" :icon="Plus" @click="addTeam('parent')"> 添加组织</el-button>
+        <el-button type="primary" :icon="Plus" @click="addTeam('parent')"> 添加组织 </el-button>
         
         <div class="collapse-wrapper">
-            <!-- 组织树v-model="activeName"-->
-            <el-collapse  accordion v-if="fetchSafetyOrganizationList.length > 0">
+            <!-- 组织树 -->
+            <el-collapse v-model="activeName" accordion v-if="fetchSafetyOrganizationList.length > 0">
                 <CollapseItem
                     v-for="item in fetchSafetyOrganizationList"
                     :key="item.id"
@@ -33,16 +34,109 @@
           @confirmAddSafetySystem="confirmAddSafetySystemCallback"
         />
       </div>
+      
       <div class="search-table-container table-content">
-        <!-- 架构图 -->
-        <OrgChart :treeData="treeData" @node-click="handleNodeClick" />
+
+        <div class="chart">
+            <!-- 架构图 -->
+            <OrgChart :treeData="treeData" @node-click="handleNodeClick" />
+        </div>
         <TeamDetailDrawer ref="teamDetailDrawerRef" :selected-team-id="selectedTeamId" />
-        <div class="text-right mb-4">
-            <el-button  @click="toStaff"> 编辑 </el-button>
+
+        <section class="content">
+
+        <div>
+            <p class="label-title">组织信息</p>
+            <el-form :model="safetyOrgUser" ref="formRef" :rules="safetyOrgUserRules">
+                <el-form-item label="组织人数" prop="userNum">
+                    <el-input placeholder="请输入组织人数" type="number" v-model="safetyOrgUser.userNum" style="width:450px" />
+                </el-form-item>
+                <el-form-item label="组织职责" prop="depResp">
+                    <el-input placeholder="请填写组织职责" v-model="safetyOrgUser.depResp"  :autosize="{ minRows: 2, maxRows: 6 }" :maxlength="300" show-word-limit type="textarea" style="width:450px" />
+                </el-form-item>
+                <el-form-item>
+                    <el-button type="primary" @click="handleSave"> 保存 </el-button>
+                </el-form-item>
+            </el-form>
+        </div>
+        <div class="mb-4">
+            <p class="label-title">人员信息</p>
+            <el-button type="primary" :icon="Plus"  @click="handleCreate"> 添加 </el-button>
+            <el-button plain  @click="handleImport">导入</el-button>
+        </div>
+        <header class="mb-4">
+          <div class="act-search">
+            <section class="select-box">
+              <div class="select-box--item">
+                <span>搜索工号/姓名:</span>
+                <el-input
+                  v-model="tableQuery.queryParam.keyword"
+                  placeholder="搜索工号/姓名"
+                  class="act-search-input"
+                />
+              </div>
+              <div class="select-box--item">
+                <span>状态:</span>
+                <el-select v-model="tableQuery.queryParam.status" placeholder="请选择状态" clearable>
+                  <el-option label="启用" :value="1" />
+                  <el-option label="禁用" :value="2" />
+                </el-select>
+              </div>
+              <div class="select-box--item">
+                <span>日期范围:</span>
+                <el-date-picker
+                  v-model="dateRange"
+                  @change="onchangeDateRange"
+                  type="daterange"
+                  range-separator="至"
+                  start-placeholder="开始日期"
+                  end-placeholder="结束日期"
+                  value-format="YYYY-MM-DD"
+                  format="YYYY-MM-DD"
+                />
+              </div>
+            </section>
+            <section class="search-btn">
+              <el-button type="primary" @click="handleSearch">查询</el-button>
+              <el-button @click="handleReset">重置</el-button>
+              <el-button plain  @click="handleDownload">导出</el-button>
+            </section>
+          </div>
+        </header>
+
+        <div class="batch-table">
+          <BasicTable
+            ref="basicTableRef"
+            :tableData="tableData"
+            :tableConfig="tableConfig"
+            @update:pageSize="handleSizeChange"
+            @update:pageNumber="handleCurrentChange"
+          >
+            <template #status="scope">
+              <span>
+                {{ scope.row.status === 1 ? '启用' : scope.row.status === 2 ? '禁用' : '-' }}
+              </span>
+            </template>
+            <template #action="scope">
+              <div class="action-container--div" style="justify-content: left">
+                <ActionButton text="编辑" @click="handleEdit(scope.row.id)" />
+                <ActionButton
+                  text="删除"
+                  :popconfirm="{
+                    title: '确定要删除?',
+                  }"
+                  @confirm="handleDelete(scope.row.id)"
+                />
+                <ActionButton text="查看" @click="handleView(scope.row.id)" />
+              </div>
+            </template>
+          </BasicTable>
         </div>
+                    
+        </section>
       </div>
     </main>
-    <!-- <BatchImport
+    <BatchImport
       v-if="batchImportVisible"
       :visible="batchImportVisible"
       :import-api-url="importApiUrl"
@@ -51,17 +145,18 @@
       :show-template="true"
       @close="batchImportVisible = false"
       @update="handleUpdate"
-    /> -->
+    />
   </div>
 </template>
 
 <script setup lang="ts">
-  import { onMounted, reactive, ref, provide } from 'vue';
+  import { onMounted, reactive, ref } from 'vue';
   import { ElMessage, ElMessageBox } from 'element-plus';
   import BasicTable from '@/components/BasicTable.vue';
   import useTableConfig from '@/hooks/useTableConfigHook';
+  import ActionButton from '@/components/ActionButton.vue';
   import { TABLE_OPTIONS, TABLE_COLUMNS } from './configs/tables';
-  import { useRouter } from 'vue-router';
+  import { useRouter, useRoute } from 'vue-router';
   import type { QueryPageRequest } from '@/types/basic-query';
   import {
     getSafetySystemList,
@@ -70,13 +165,16 @@
     deleteSafetySystem,
     fetchTableList,
     delEmployee,
+    safetyOrgUserSave,
+    safetyOrgUserDetail,
     exportSafetyOrganizationSystemManagement
   } from '@/api/safety-organization-management';
-//   import { downloadByData } from '@/utils/file/download';
-//   import BatchImport from '@/components/batch-import/BatchImport.vue';
-//   import { useGlobSetting } from '@/hooks/setting';
-//   import urlJoin from 'url-join';
+  import { downloadByData } from '@/utils/file/download';
+  import BatchImport from '@/components/batch-import/BatchImport.vue';
+  import { useGlobSetting } from '@/hooks/setting';
+  import urlJoin from 'url-join';
   import AddSafetySystem from './components/addSafetySystem.vue';
+  import {SafetyOrgUserRules} from "./configs/form"
   import {
   Delete,
   Edit,
@@ -86,37 +184,17 @@
   import CollapseItem from './components/collapseItem.vue'
   import TeamDetailDrawer from './components/TeamDetailDrawer.vue';
 const position = ref('left')
-
+  const route = useRoute();
   const router = useRouter();
   // 表格
-//   const basicTableRef = ref<InstanceType<typeof BasicTable>>();
+  const basicTableRef = ref<InstanceType<typeof BasicTable>>();
 
   const { tableConfig, pagination } = useTableConfig(TABLE_COLUMNS, TABLE_OPTIONS);
 
   const tableData = ref<any[]>([]);
 
   const fetchSafetyOrganizationList = ref<any[]>([]);
-
-  const activeName = ref('');
-  // 给组件递归时使用
-//   provide('activeName', activeName)
-
-  const level = ref(1)
-  // 日期范围(用于日期选择器)
-  const dateRange = ref<[string, string] | string>('');
-
-  const tableQuery = reactive<QueryPageRequest<any>>({
-    pageNumber: pagination.pageNumber,
-    pageSize: pagination.pageSize,
-    queryParam: {
-      classifyName: '',
-      keyword: '',
-      status: '',
-      startTime: '',
-      endTime: '',
-    },
-  });
-
+// 架构数据类型
   type OrganizationTreeType = {
     id: string;
     data: { name: string };
@@ -128,22 +206,6 @@ const position = ref('left')
     data: { name: '请添加组织' },
     children: [],
   });
-  
-//   const handlerEdit = ()=>{
-//     router.push({name: 'securityOrganizationalStructure'})
-//   }
-//   const handleSizeChange = (value: number) => {
-//     pagination.pageSize = value;
-//     tableQuery.pageSize = value;
-//     getTableData();
-//   };
-
-//   const handleCurrentChange = (value: number) => {
-//     pagination.pageNumber = value;
-//     tableQuery.pageNumber = value;
-//     getTableData();
-//   };
-
   const teamDetailDrawerRef = ref<InstanceType<typeof TeamDetailDrawer>>();
   const selectedTeamId = ref<number | null>(null);
   const handleNodeClick = (nodeData: any) => {
@@ -153,22 +215,89 @@ const position = ref('left')
 
     teamDetailDrawerRef.value?.drawerShow();
   };
-//   async function getTableData() {
-//     tableConfig.loading = true;
-//     try {
-//       const res = await fetchTableList(tableQuery);
-//       if (res) {
-//         tableData.value = res.records
-//         pagination.total = res.totalRow;
-//       }
-//     } catch (e) {
-//       console.error('获取列表失败:', e);
-//       tableData.value = [];
-//       pagination.total = 0;
-//     } finally {
-//       tableConfig.loading = false;
-//     }
-//   }
+
+  const activeName = ref('');
+  // 日期范围(用于日期选择器)
+  const dateRange = ref<[string, string] | string>('');
+  const level = ref(1)
+  const tableQuery = reactive<QueryPageRequest<any>>({
+    pageNumber: pagination.pageNumber,
+    pageSize: pagination.pageSize,
+    queryParam: {
+      classifyName: '',
+      keyword: '',
+      status: '',
+      startTime: '',
+      endTime: '',
+    },
+  });
+  const safetyOrgUser = reactive({
+    id: 0,
+    userNum: '',
+    depResp: ''
+  })
+  const formRef = ref()
+  const safetyOrgUserRules = ref(SafetyOrgUserRules)
+  // 校验员工数量和职责
+  const handleValidate = async () => {
+    if (!formRef.value) return;
+    const res = await formRef.value.validateField();
+    return res;
+  };
+  // 保存员工数量和职责
+  const handleSave = async ()=>{
+    const res = await handleValidate()
+    if (!res) return;
+    try {
+        console.log(safetyOrgUser, 'canshu')
+        safetyOrgUser.id = Number(safetyOrgUser.id)
+        await safetyOrgUserSave(safetyOrgUser)
+        ElMessage.success('保存成功');
+    } catch (error) {
+        ElMessage.error('保存失败');
+    }
+  }
+  // 查询组织详情
+  const safetyOrgDetail = async (id)=>{
+    try {
+        const res = await safetyOrgUserDetail(id)
+        Object.assign(safetyOrgUser, {
+            id,
+            userNum: res.userNum,
+            depResp: res.depResp
+        })
+    } catch (error) {
+        ElMessage.error('获取详情失败');
+    }
+  }
+  const handleSizeChange = (value: number) => {
+    pagination.pageSize = value;
+    tableQuery.pageSize = value;
+    getTableData();
+  };
+
+  const handleCurrentChange = (value: number) => {
+    pagination.pageNumber = value;
+    tableQuery.pageNumber = value;
+    getTableData();
+  };
+
+  async function getTableData() {
+    tableConfig.loading = true;
+    try {
+      const res = await fetchTableList(tableQuery);
+      if (res) {
+        tableData.value = res.records
+        pagination.total = res.totalRow;
+      }
+    } catch (e) {
+      console.error('获取列表失败:', e);
+      tableData.value = [];
+      pagination.total = 0;
+    } finally {
+      tableConfig.loading = false;
+    }
+  }
 
   interface addSafetyOrganizationSystemFormDataType {
     type: String;
@@ -186,7 +315,6 @@ const position = ref('left')
     action: '',
     parentid: '',
   });
-
 /**
  * 递归给树形结构添加 id 、data 、children 字段
  * @param {Array} tree 原始树形数组
@@ -213,6 +341,7 @@ const formatTreeData = (tree)=> {
     return formattedItem;
   });
 }
+
   function convertData(leaderTeams): OrganizationTreeType {
     return {
       id: `org-${leaderTeams.orgId}`, 
@@ -222,6 +351,7 @@ const formatTreeData = (tree)=> {
       children: leaderTeams.children?.map((child) => convertData(child)),
     };
   }
+
   // 获取组织列表
   const fetchSafetyOrganizationTeamList = async () => {
     try {
@@ -230,7 +360,7 @@ const formatTreeData = (tree)=> {
       // 默认选择第一个组织
       if(res[0].orgId){
         treeNodePreview(res[0])
-        activeName.value = String(res[0].orgId)
+        // activeName.value = String(res[0].orgId)
         tableQuery.queryParam.classifyName = res[0].orgId
       }
 
@@ -252,7 +382,8 @@ const formatTreeData = (tree)=> {
     };
     addSafetySystemVisible.value = true;
   };
-  // 子级新增
+
+    // 子级新增
   const handleCreateSafetySystem = async (type, value) => {
     // console.log('新增参数--',type, value)
     addSafetyOrganizationSystemFormData.value = {
@@ -277,34 +408,16 @@ const formatTreeData = (tree)=> {
       parentid,
     };
   };
-
-  // 删除
-  const handleDelSafetySystem = async (type, value) => {
-    // console.log('删除', type, value)
-    ElMessageBox.confirm('确认删除该组织吗?', '警告', { type: 'warning' }).then(async () => {
-      try {
-        if(value.children.length > 0){
-            ElMessage.error('当前一级组织存在子级数据,无法删除,请先删除子级组织')
-            return 
-        }
-        await deleteSafetySystem(value.orgId);
-        ElMessage.success('删除成功');
-        // 刷新组织列表
-        fetchSafetyOrganizationTeamList();
-      } catch (error) {
-        ElMessage.error(error || '删除失败');
-      }
-    });
-  };
   // 查询
   const querySafetyTeamData = (value) => {
     // console.log('查询', value);
     tableQuery.queryParam.classifyName = value.orgId;
-    activeName.value = String(value.orgId)
+    // activeName.value = String(value.orgId)
     treeNodePreview(value)
+    safetyOrgDetail(value.orgId)
+    getTableData();
   };
-
-    // 定义组织数据类型
+  // 定义组织数据类型
   interface SafetySystemFormData {
     value: string; // 输入的组织名称
     action: 'add' | 'edit'; // 操作类型:新增或编辑
@@ -349,112 +462,144 @@ const formatTreeData = (tree)=> {
       ElMessage.error(formData.action === 'add' ? '新增组织失败!' : '编辑组织失败!');
     }
   };
+    // 删除
+  const handleDelSafetySystem = async (type, value) => {
+    // console.log('删除', type, value)
+    ElMessageBox.confirm('确认删除该组织吗?', '警告', { type: 'warning' }).then(async () => {
+      try {
+        if(value.children.length > 0){
+            ElMessage.error('当前一级组织存在子级数据,无法删除,请先删除子级组织')
+            return 
+        }
+        await deleteSafetySystem(value.orgId);
+        ElMessage.success('删除成功');
+        // 刷新组织列表
+        fetchSafetyOrganizationTeamList();
+        handleReset();
+      } catch (error) {
+        ElMessage.error(error || '删除失败');
+      }
+    });
+  };
 
-  const toStaff = ()=>{
-    router.push({name: 'securityOrganizationalStructure', query: {id: tableQuery.queryParam.classifyName}})
+  
+  // 定义组织数据类型
+  interface SafetySystemFormData {
+    value: string; // 输入的组织名称
+    action: 'add' | 'edit'; // 操作类型:新增或编辑
+    orgId?: string | number; // 组织ID(编辑时必传)
+    parentid?: string | number; // 父组织ID(新增子组织时必传)
+    type?: 'children' | 'parent'; // 组织类型(子组织或根组织)
   }
+
   // 时间查询
-//   const onchangeDateRange = () => {
-//     if (dateRange.value && Array.isArray(dateRange.value) && dateRange.value.length === 2) {
-//       tableQuery.queryParam.startTime = dateRange.value[0] || '';
-//       tableQuery.queryParam.endTime = dateRange.value[1] || '';
-//     } else {
-//       tableQuery.queryParam.startTime = '';
-//       tableQuery.queryParam.endTime = '';
-//     }
-//     getTableData();
-//   };
-//   const handleSearch = () => {
-//     pagination.pageNumber = 1;
-//     tableQuery.pageNumber = 1;
-//     getTableData();
-//   };
-
-//   const handleReset = () => {
-//     pagination.pageNumber = 1;
-//     tableQuery.queryParam = {
-//       classifyName: '',
-//       keyword: '',
-//       status: '', // 重置为默认启用状态
-//       startTime: '',
-//       endTime: '',
-//     };
-//     dateRange.value = '';
-//     handleSearch();
-//   };
+  const onchangeDateRange = () => {
+    if (dateRange.value && Array.isArray(dateRange.value) && dateRange.value.length === 2) {
+      tableQuery.queryParam.startTime = dateRange.value[0] || '';
+      tableQuery.queryParam.endTime = dateRange.value[1] || '';
+    } else {
+      tableQuery.queryParam.startTime = '';
+      tableQuery.queryParam.endTime = '';
+    }
+    getTableData();
+  };
+  const handleSearch = () => {
+    pagination.pageNumber = 1;
+    tableQuery.pageNumber = 1;
+    getTableData();
+  };
+
+  const handleReset = () => {
+    pagination.pageNumber = 1;
+    tableQuery.queryParam = {
+      classifyName: '',
+      keyword: '',
+      status: '', // 重置为默认启用状态
+      startTime: '',
+      endTime: '',
+    };
+    dateRange.value = '';
+    handleSearch();
+  };
 
   // 批量导入
-//   const batchImportVisible = ref(false);
-//   const { urlPrefix } = useGlobSetting();
-//   const importApiUrl = ref(urlJoin(urlPrefix, '/safetyorguser/importSafetyOrgUser'));
-//   const templateUrl = ref('./skyeye-file-upload/sfysecurity/TEMPLATE/安全组织体系管理导入模版.xlsx');
-
-//   const handleImport = () => {
-//     batchImportVisible.value = true;
-//   };
-
-//   const handleUpdate = () => {
-//     batchImportVisible.value = false;
-//     getTableData();
-//   };
-
-//   const handleDownload = async () => {
-//     try {
-//       const response = await exportSafetyOrganizationSystemManagement(tableQuery.queryParam);
-//       if (response) {
-//         const fileName = `安全组织体系管理_${new Date().toISOString().split('T')[0]}.xlsx`;
-//         downloadByData(response, fileName);
-//         ElMessage.success('导出成功');
-//       }
-//     } catch (e) {
-//       console.error('导出安全组织体系管理失败:', e);
-//       ElMessage.error('导出失败,请重试');
-//     }
-//   };
-
-//   const handleCreate = () => {
-//     router.push({
-//       name: 'SafetyOrganizationSystemManagementItem',
-//       query: {
-//         operate: 'employee-create',
-//       },
-//     });
-//   };
-
-//   const handleEdit = (id: number) => {
-//     router.push({
-//       name: 'SafetyOrganizationSystemManagementItem',
-//       query: {
-//         id,
-//         operate: 'employee-edit',
-//       },
-//     });
-//   };
-
-//   const handleDelete = async (id: number) => {
-//     try {
-//       await delEmployee(id);
-//       ElMessage.success('删除成功');
-//       getTableData();
-//     } catch (e) {
-//       console.error('删除员工失败:', e);
-//       ElMessage.error('删除失败,请重试');
-//     }
-//   };
-
-//   const handleView = (id: number) => {
-//     router.push({
-//       name: 'SafetyOrganizationSystemManagementItem',
-//       query: {
-//         id,
-//         operate: 'employee-view',
-//       },
-//     });
-//   };
-
-  onMounted(() => {
+  const batchImportVisible = ref(false);
+  const { urlPrefix } = useGlobSetting();
+  const importApiUrl = ref(urlJoin(urlPrefix, '/safetyorguser/importSafetyOrgUser'));
+  const templateUrl = ref('./skyeye-file-upload/sfysecurity/TEMPLATE/安全组织体系管理导入模版.xlsx');
+
+  const handleImport = () => {
+    batchImportVisible.value = true;
+  };
+
+  const handleUpdate = () => {
+    batchImportVisible.value = false;
+    getTableData();
+  };
+
+  const handleDownload = async () => {
+    try {
+      const response = await exportSafetyOrganizationSystemManagement(tableQuery.queryParam);
+      if (response) {
+        const fileName = `安全组织体系管理_${new Date().toISOString().split('T')[0]}.xlsx`;
+        downloadByData(response, fileName);
+        ElMessage.success('导出成功');
+      }
+    } catch (e) {
+      console.error('导出安全组织体系管理失败:', e);
+      ElMessage.error('导出失败,请重试');
+    }
+  };
+
+  const handleCreate = () => {
+    router.push({
+      name: 'SecurityOrganizationalStructureItem',
+      query: {
+        operate: 'employee-create',
+      },
+    });
+  };
+
+  const handleEdit = (id: number) => {
+    router.push({
+      name: 'SecurityOrganizationalStructureItem',
+      query: {
+        id,
+        operate: 'employee-edit',
+      },
+    });
+  };
+
+  const handleDelete = async (id: number) => {
+    try {
+      await delEmployee(id);
+      ElMessage.success('删除成功');
+      getTableData();
+    } catch (e) {
+      console.error('删除员工失败:', e);
+      ElMessage.error('删除失败,请重试');
+    }
+  };
+
+  const handleView = (id: number) => {
+    router.push({
+      name: 'SecurityOrganizationalStructureItem',
+      query: {
+        id,
+        operate: 'employee-view',
+      },
+    });
+  };
+  onMounted(async () => {
     fetchSafetyOrganizationTeamList();
-    // getTableData();
+    // 默认第一个架构组织的员工数据
+    const res = await getSafetySystemList();
+    const orgId = res[0]?.orgId;
+    tableQuery.queryParam.classifyName = orgId || undefined
+    getTableData();
+    if(orgId){
+        safetyOrgDetail(orgId)
+    }
   });
 </script>
 
@@ -463,17 +608,23 @@ const formatTreeData = (tree)=> {
   @use '@/styles/page-main-layout.scss' as *;
   @use '@/styles/basic-table-action.scss' as *;
   @use '@/views/traffic/violation/style/act-search-table.scss' as *;
- .text-right{
-    text-align: right;
- }
- .mb-4{
-    margin-bottom: 12px;
+  .platform-main {
+    width:100%;
+  }
+  .table-content {
+    flex:1;
+    width: 0;
+    min-width: 0;
+  }
+   .mb-4{
+    margin-bottom: 16px;
  }
   .nav {
     flex: 0 0 300px;
     margin-right: 15px;
     padding-right: 15px;
     border-right: 1px solid #eee;
+    overflow-y: auto;
     :deep(.collapse-title) {
         flex: 1 0 90%;
         order: 1;
@@ -520,4 +671,17 @@ const formatTreeData = (tree)=> {
       }
     }
   }
+  .label-title{
+    margin-bottom:16px;
+  }
+  .chart {
+    height:260px;
+    background-color: #f1f7ff;
+    border-radius: 4px;
+    overflow: hidden;
+  }
+  .content {
+    height: calc(100% - 260px - 32px);
+    overflow-y: auto;
+  }
 </style>

+ 123 - 0
src/views/production-safety/productionSafetySystem/securityOrganizationalStructure/components/TeamDetailDrawer.vue

@@ -0,0 +1,123 @@
+<template>
+  <el-drawer v-model="showDrawer" direction="rtl" @close="clearData">
+    <div class="team-detail__info">
+      <div class="team-detail__info__team-name">{{ organization?.orgName }}</div>
+      <div class="team-detail__info__member-count">
+        共 <span>{{ organization?.userNum || 0 }}</span> 人
+      </div>
+    </div>
+    <div class="team-detail__description">
+      <div class="team-detail__description__title"> 组织职责 </div>
+      <div class="team-detail__description__content"> {{ organization?.depResp || '暂无职责'}} </div>
+    </div>
+  </el-drawer>
+</template>
+
+<script setup lang="ts">
+  import { ref, watch } from 'vue';
+  import {
+    safetyOrgUserDetail,
+  } from '@/api/safety-organization-management';
+  const props = defineProps<{ selectedTeamId: number | null }>();
+
+  type LevelAndPersonType = {
+    positionLevel: number;
+    title: string;
+    personList: string[];
+  };
+ interface OrganizationInfoType {
+     createdAt: Date;
+     createdBy: number;
+     depResp: string;
+     id: number;
+     isDeleted: number;
+     orgName: string;
+     parentId: number;
+     updatedAt: Date;
+     userNum: number;
+};
+
+
+  const showDrawer = ref(false);
+  const organization = ref<OrganizationInfoType>();
+
+  function drawerShow() {
+    showDrawer.value = true;
+  }
+
+  function clearData() {
+    organization.value = undefined;
+  }
+
+  watch(
+    () => showDrawer.value,
+    async () => {
+      if (showDrawer.value) {
+        organization.value = await safetyOrgUserDetail(props.selectedTeamId!);
+      }
+    },
+  );
+
+  defineExpose({
+    drawerShow,
+  });
+</script>
+
+<style scoped lang="scss">
+  .team-detail__info {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: 20px;
+
+    &__team-name {
+      font-size: 20px;
+      font-weight: bold;
+    }
+    &__member-count {
+      span {
+        color: #1777ff;
+      }
+    }
+  }
+
+  .team-detail__level {
+    display: flex;
+    align-items: center;
+    margin-bottom: 10px;
+    padding: 10px 0;
+    border-left: 3px solid #1777ff;
+    background-color: #e5effe;
+
+    &__title {
+      flex: 1;
+      height: inherit;
+      padding: 0 10px;
+      color: #1777ff;
+      text-align: center;
+      white-space: nowrap;
+    }
+
+    &__content {
+      flex: 10;
+      display: flex;
+      flex-wrap: wrap;
+      padding: 0 15px;
+      gap: 15px;
+      border-left: 1px solid #c5c3c3;
+    }
+  }
+
+  .team-detail__description {
+    margin-top: 20px;
+    &__title {
+      margin-bottom: 10px;
+      font-size: 16px;
+      font-weight: bold;
+    }
+    &__content {
+      color: #aaaaaa;
+      white-space: pre-wrap;
+    }
+  }
+</style>

+ 151 - 0
src/views/production-safety/productionSafetySystem/securityOrganizationalStructure/components/collapseItem.vue

@@ -0,0 +1,151 @@
+<template>
+  <div v-if="level <= 10">
+    <el-collapse-item :name="String(data.orgId)">
+      <!-- 标题 -->
+      <template #title>
+        <div class="node" :style="{ marginLeft: (level - 1) * 2 + 'px' }">
+            <div @click.stop="handleClick" class="cursor-pointer">
+            {{ data?.orgName }}
+            </div>
+            <el-popconfirm hide-icon  popper-class="node-popconfirm">
+                <template #reference>
+                    <el-button size="small" class="handle" :icon="MoreFilled" @click.stop />
+                </template>
+                <template #actions="{ confirm, cancel }">
+                    <ul>
+                        <li><el-button type="primary" link :icon="Plus" @click.stop="bindingEvents('create', 'children', data)">新增</el-button></li>
+                        <li><el-button type="primary" link :icon="Edit" @click.stop="bindingEvents('edit', 'children', data)">编辑</el-button></li>
+                        <li><el-button type="primary" link :icon="Delete" @click.stop="bindingEvents('delate', 'children', data)">删除</el-button></li>
+                    </ul>
+                </template>
+            </el-popconfirm>
+        </div>
+      </template>
+
+      <!-- 子级递归 -->
+      <div
+        v-if="data.children && data.children.length && level < 10"
+        class="ml-4">
+        <el-collapse  accordion>
+          <CollapseItem
+            v-for="child in data.children"
+            :key="child.id"
+            :data="child"
+            :level="level + 1"
+            @click-node="handleClickItem"
+            @create-node="(type, item) => emit('create-node', type, item)"
+            @edit-node="(type, item) => emit('edit-node', type, item)"
+            @delete-node="(type, item) => emit('delete-node', type, item)"
+          />
+        </el-collapse>
+      </div>
+      <div v-else>
+        <el-empty description="未添加子组织" :image-size="40" />
+      </div>
+    </el-collapse-item>
+  </div>
+</template>
+
+<script setup>
+  import { defineProps, defineEmits, defineOptions, ref, inject } from 'vue'
+  import {
+  Delete,
+  Edit,
+  Plus,
+  MoreFilled
+} from '@element-plus/icons-vue'
+// 必须给组件命名,才能递归
+defineOptions({
+  name: 'CollapseItem'
+})
+const childrenActiveName = ref('')
+// const activeName = inject('activeName')
+// 定义 props
+const props = defineProps({
+  data: {
+    type: Object,
+    required: true
+  },
+  level: {
+    type: Number,
+    default: 1
+  }
+})
+
+// 定义事件
+const emit = defineEmits(['click-node', 'create-node', 'edit-node', 'delete-node'])
+// 新增、编辑、删除事件
+const bindingEvents = (state, type, item)=>{
+    switch(state){
+        case 'create':
+            emit('create-node',type, item)
+            break;
+        case 'edit':
+            emit('edit-node',type, item)
+            break;
+        case 'delate':
+            emit('delete-node',type, item)
+            break;
+        default:
+            emit('create-node',type, item)
+    }
+}
+// 点击当前项
+const handleClick = () => {
+  emit('click-node', props.data)
+//   activeName.value = String(props.data.orgId)
+}
+
+// 接收子组件点击
+const handleClickItem = (item) => {
+  emit('click-node', item)
+//   activeName.value = String(item.orgId)
+}
+</script>
+
+<style scoped>
+.ml-4 {
+  margin-left: 16px;
+}
+.cursor-pointer {
+  cursor: pointer;
+}
+.node {
+  display:flex;
+  justify-content: space-between;
+  align-items: center;
+  width: 100%;
+}
+.handle {
+    margin-right: 8px;
+}
+li{
+    list-style: none;
+    width:100%;
+    text-align: center;
+    padding:4px 0;
+    margin: 4px 0;
+    cursor: pointer;
+}
+/* 全局生效 /deep/ 穿透 */
+/* :deep(.el-collapse-item__header) {
+  border-left: 3px solid transparent;
+  transition: all 0.2s;
+} */
+
+/* 选中展开的项 → 高亮 */
+/* :deep(.el-collapse-item__header.is-active) {
+  background-color: #f5f7fa !important;
+  border-left: 3px solid #1677ff;
+} */
+
+/* 选中的标题文字高亮 */
+/* :deep(.el-collapse-item__header.is-active .node) {
+  color: #1677ff !important;
+} */
+
+/* hover 效果 */
+/* :deep(.el-collapse-item__header:hover) {
+  background: #fafafa;
+} */
+</style>

+ 195 - 0
src/views/production-safety/productionSafetySystem/securityOrganizationalStructure/components/orgChart.vue

@@ -0,0 +1,195 @@
+<template>
+  <div class="org-chart-container" ref="container"></div>
+</template>
+
+<script setup lang="ts">
+  import { ref, onMounted, onBeforeUnmount, watch, nextTick } from 'vue';
+  import { Graph, treeToGraphData, NodeEvent, CanvasEvent } from '@antv/g6';
+  // import { Graph, treeToGraphData, register, ExtensionCategory, NodeEvent, Polyline, CanvasEvent } from '@antv/g6';
+
+  /**
+   * @description: 为了确保图的正确渲染和交互,建议按照 G6 标准数据结构组织数据。
+   * 每个元素(节点、边、组合)应包含一个 data 字段,用于存放业务数据和自定义属性。
+   */
+
+  // 定义 props 接口
+  interface TreeData {
+    id: string;
+    data: { name: string };
+    children?: TreeData[];
+  }
+
+  const props = defineProps<{
+    treeData: TreeData;
+  }>();
+
+  const emits = defineEmits<{
+    (event: 'node-click', nodeData: any): void;
+    (event: 'canvas-click'): void;
+  }>();
+
+  let data = treeToGraphData(props.treeData); // 通过 treeToGraphData 方法,将树形结构数据转换为 G6 的标准数据结构
+  const container = ref<HTMLDivElement | null>(null); // 图表容器引用
+  let graph: any = null;
+  let pending = false; // 防止并发 initGraph
+
+  // 初始化图表
+  const initGraph = async () => {
+    if (pending || !container.value) return;
+    pending = true;
+
+    // 销毁旧实例
+    if (graph) {
+      graph.off();
+      graph.destroy();
+      graph = null;
+    }
+
+    // 等待下一帧,确保销毁完成
+    await nextTick();
+
+    // 创建新的 G6 实例
+    graph = new Graph({
+      container: container.value,
+      padding: [20, 20, 20, 20], // 图表内边距
+      data,
+      node: {
+        type: 'rect', // 使用内置的矩形节点类型
+        style: {
+          labelText: (d: any) => d.data.name, // 节点文本
+          labelFill: '#333', // 文本颜色
+          labelFontSize: 14, // 文本大小
+          size: [250, 50],
+          lineWidth: 1, // 边框宽度
+          // lineDash: [5, 5], // 虚线边框
+          stroke: '#1777FF', // 边框色
+          fill: '#E7F1FF', // 填充色
+          radius: 8,
+          labelPlacement: 'center',
+          ports: [{ placement: 'top' }, { placement: 'bottom' }],
+        },
+        // 节点状态样式
+        state: {
+          selected: {
+            fill: '#1777FF',
+            stroke: '#1777FF',
+            lineWidth: 1,
+            labelFill: '#fff', // 选中状态下文本颜色
+            labelFontSize: 16, // 选中状态下文本大小
+          },
+        },
+      },
+      edge: {
+        type: 'ant-line', // 边类型
+        style: {
+          stroke: '#1777FF', // 边的颜色
+          lineWidth: 1, // 边的宽度
+          lineDash: [10, 10],
+          endArrow: true, // 是否有箭头
+          router: {
+            type: 'orth',
+          },
+        },
+      },
+      layout: {
+        type: 'dagre',
+        nodesep: 100,
+        ranksep: 120,
+        preventOverlap: true, // 防止节点重叠
+        nodeStrength: -50, // 节点之间的斥力
+        edgeStrength: 0.5, // 边的弹性系数
+        iterations: 200, // 迭代次数
+        animation: true, // 启用布局动画
+      },
+      autoFit: {
+        type: 'center', // 自适应类型:'view' 或 'center'
+        // options: {
+        //   // 仅适用于 'view' 类型
+        //   when: 'always', // 何时适配:'overflow'(仅当内容溢出时) 或 'always'(总是适配)
+        //   direction: 'both', // 适配方向:'x'、'y' 或 'both'
+        // },
+        // animation: {
+        //   // 自适应动画效果
+        //   duration: 1000, // 动画持续时间(毫秒)
+        //   easing: 'ease-in-out', // 动画缓动函数
+        // },
+      },
+      autoResize: true, // 自动调整大小
+      behaviors: [
+        'drag-canvas',
+        {
+          type: 'zoom-canvas',
+          sensitivity: 0.5, // 配置灵敏度
+          key: 'zoom-behavior', // 为交互指定key,便于后续更新
+        },
+        'focus-element',
+        {
+          type: 'click-select',
+          state: 'selected',
+          unselectedState: 'inactive',
+          multiple: true,
+          trigger: ['shift'],
+        },
+      ],
+    });
+
+    // 渲染
+    graph.render();
+
+    // 监听节点点击事件
+    graph.on(NodeEvent.CLICK, (evt) => {
+      const { target } = evt;
+      const nodeData = graph.getNodeData(target.id); // 获取节点数据
+      emits('node-click', nodeData);
+    });
+
+    graph.on(CanvasEvent.CLICK, () => {
+      graph?.fitCenter();
+      emits('canvas-click');
+    });
+
+    window.addEventListener('resize', handleResize);
+
+    pending = false;
+  };
+
+  // 处理窗口大小变化
+  const handleResize = () => {
+    if (graph && container.value) {
+      graph.resize(container.value.offsetWidth, container.value.offsetHeight);
+      graph.fitCenter();
+    }
+  };
+
+  // 监听 treeData 变化
+  watch(
+    () => props.treeData,
+    () => {
+      data = treeToGraphData(props.treeData);
+      initGraph();
+    },
+    { deep: true },
+  );
+
+  // 生命周期钩子
+  onMounted(() => {
+    data = treeToGraphData(props.treeData);
+    initGraph();
+  });
+
+  onBeforeUnmount(() => {
+    window.removeEventListener('resize', handleResize);
+    if (graph) {
+      graph.off(); // 移除所有事件监听
+      graph.destroy();
+      graph = null;
+    }
+  });
+</script>
+
+<style lang="scss" scoped>
+  .org-chart-container {
+    width: 100%;
+    height: 260px;
+  }
+</style>

+ 11 - 11
src/views/production-safety/productionSafetySystem/securityOrganizationalStructure/configs/tables.ts

@@ -2,7 +2,7 @@
  * @Author: liuJie
  * @Date: 2026-01-27 16:29:28
  * @LastEditors: liuJie
- * @LastEditTime: 2026-03-30 13:42:36
+ * @LastEditTime: 2026-04-10 14:03:52
  * @Describe: file describe
  */
 import type { TableColumnProps } from '@/types/basic-table';
@@ -21,15 +21,15 @@ export const TABLE_COLUMNS: TableColumnProps[] = [
     align: 'center',
     width: '80px',
   },
-  {
-    label: '员工工号',
-    prop: 'employeeId',
-    align: 'left',
+    {
+    label: '员工姓名',
+    prop: 'employeeName',
+    align: 'center',
     minWidth: '120px',
   },
   {
-    label: '员工姓名',
-    prop: 'employeeName',
+    label: '员工工号',
+    prop: 'employeeId',
     align: 'center',
     minWidth: '120px',
   },
@@ -37,27 +37,27 @@ export const TABLE_COLUMNS: TableColumnProps[] = [
     label: '状态',
     prop: 'status',
     slot: 'status',
-    align: 'left',
+    align: 'center',
     minWidth: '90px',
   },
 
   {
     label: '组织名称',
     prop: 'orgName',
-    align: 'left',
+    align: 'center',
     minWidth: '140px',
   },
     {
     label: '岗位名称',
     prop: 'jobName',
-    align: 'left',
+    align: 'center',
     minWidth: '150px',
     showOverflowTooltip: true,
   },
   {
     label: '岗位职责',
     prop: 'jobResp',
-    align: 'left',
+    align: 'center',
     minWidth: '150px',
     showOverflowTooltip: true,
   },

+ 164 - 50
src/views/production-safety/productionSafetySystem/securityOrganizationalStructure/securityOrganizationalStructure.vue

@@ -33,7 +33,17 @@
           @confirmAddSafetySystem="confirmAddSafetySystemCallback"
         />
       </div>
+      
       <div class="search-table-container table-content">
+
+        <div class="chart">
+            <!-- 架构图 -->
+            <OrgChart :treeData="treeData" @node-click="handleNodeClick" />
+        </div>
+        <TeamDetailDrawer ref="teamDetailDrawerRef" :selected-team-id="selectedTeamId" />
+
+        <section class="content">
+
         <div>
             <p class="label-title">组织信息</p>
             <el-form :model="safetyOrgUser" ref="formRef" :rules="safetyOrgUserRules">
@@ -48,12 +58,12 @@
                 </el-form-item>
             </el-form>
         </div>
-        <div>
+        <div class="mb-4">
             <p class="label-title">人员信息</p>
             <el-button type="primary" :icon="Plus"  @click="handleCreate"> 添加 </el-button>
             <el-button plain  @click="handleImport">导入</el-button>
         </div>
-        <header>
+        <header class="mb-4">
           <div class="act-search">
             <section class="select-box">
               <div class="select-box--item">
@@ -121,6 +131,8 @@
             </template>
           </BasicTable>
         </div>
+                    
+        </section>
       </div>
     </main>
     <BatchImport
@@ -167,7 +179,9 @@
   Edit,
   Plus,
 } from '@element-plus/icons-vue'
-import CollapseItem from '../safetyOrganizationSystemManagement/components/collapseItem.vue'
+  import OrgChart from './components/orgChart.vue';
+  import CollapseItem from './components/collapseItem.vue'
+  import TeamDetailDrawer from './components/TeamDetailDrawer.vue';
 const position = ref('left')
   const route = useRoute();
   const router = useRouter();
@@ -179,6 +193,27 @@ const position = ref('left')
   const tableData = ref<any[]>([]);
 
   const fetchSafetyOrganizationList = ref<any[]>([]);
+// 架构数据类型
+  type OrganizationTreeType = {
+    id: string;
+    data: { name: string };
+    children?: OrganizationTreeType[];
+  };
+
+  const treeData = ref<OrganizationTreeType>({
+    id: 'root',
+    data: { name: '请添加组织' },
+    children: [],
+  });
+  const teamDetailDrawerRef = ref<InstanceType<typeof TeamDetailDrawer>>();
+  const selectedTeamId = ref<number | null>(null);
+  const handleNodeClick = (nodeData: any) => {
+      const id = nodeData?.id?.replace('org-', '')
+      console.log(nodeData, 'canshu')
+    selectedTeamId.value = Number(id);
+
+    teamDetailDrawerRef.value?.drawerShow();
+  };
 
   const activeName = ref('');
   // 日期范围(用于日期选择器)
@@ -279,23 +314,108 @@ const position = ref('left')
     action: '',
     parentid: '',
   });
-  // 一级新增
-  const addTeam = (type) => {
-    addSafetyOrganizationSystemFormData.value = {
-      type,
-      action: 'add',
+/**
+ * 递归给树形结构添加 id 、data 、children 字段
+ * @param {Array} tree 原始树形数组
+ * @returns 格式化后的标准树结构
+ */
+const formatTreeData = (tree)=> {
+  if (!tree || !Array.isArray(tree)) return [];
+
+  return tree.map(item => {
+    // 给每一层节点都加上 id 和 data
+    const formattedItem = {
+      children: item.children || [],
+      id: `org-${item.orgId}`, 
+      data: {
+        name: item.orgName
+      }
     };
-    addSafetySystemVisible.value = true;
-  };
+
+    // 递归处理子节点
+    if (formattedItem.children && formattedItem.children.length > 0) {
+      formattedItem.children = formatTreeData(formattedItem.children);
+    }
+
+    return formattedItem;
+  });
+}
+
+  function convertData(leaderTeams): OrganizationTreeType {
+    return {
+      id: `org-${leaderTeams.orgId}`, 
+      data: {
+        name: leaderTeams.orgName
+      },
+      children: leaderTeams.children?.map((child) => convertData(child)),
+    };
+  }
+
   // 获取组织列表
   const fetchSafetyOrganizationTeamList = async () => {
     try {
       const res = await getSafetySystemList();
       fetchSafetyOrganizationList.value = res;
+      // 默认选择第一个组织
+      if(res[0].orgId){
+        treeNodePreview(res[0])
+        // activeName.value = String(res[0].orgId)
+        tableQuery.queryParam.classifyName = res[0].orgId
+      }
+
     } catch (error) {
       ElMessage.error('获取组织列表失败');
     }
   };
+  // 给架构图赋值
+  const treeNodePreview = (data)=>{
+    let TreeNode = convertData(data)
+    treeData.value = TreeNode
+  }
+
+  // 一级新增
+  const addTeam = (type) => {
+    addSafetyOrganizationSystemFormData.value = {
+      type,
+      action: 'add',
+    };
+    addSafetySystemVisible.value = true;
+  };
+
+    // 子级新增
+  const handleCreateSafetySystem = async (type, value) => {
+    // console.log('新增参数--',type, value)
+    addSafetyOrganizationSystemFormData.value = {
+      type:'children',
+      action: 'add',
+      orgName: value.orgName,
+      orgId: value.orgId,
+    };
+    addSafetySystemVisible.value = true;
+    // 打开某一个
+    // activeName.value = value.orgId;
+  };
+  // 编辑
+  const handleEditSafetySystem = (type, value, parentid) => {
+    // console.log('编辑参数--', type, value, parentid)
+    addSafetySystemVisible.value = true;
+    addSafetyOrganizationSystemFormData.value = {
+      type,
+      action: 'edit',
+      orgName: value.orgName,
+      orgId: value.orgId,
+      parentid,
+    };
+  };
+  // 查询
+  const querySafetyTeamData = (value) => {
+    // console.log('查询', value);
+    tableQuery.queryParam.classifyName = value.orgId;
+    // activeName.value = String(value.orgId)
+    treeNodePreview(value)
+    safetyOrgDetail(value.orgId)
+    getTableData();
+  };
   // 定义组织数据类型
   interface SafetySystemFormData {
     value: string; // 输入的组织名称
@@ -304,20 +424,22 @@ const position = ref('left')
     parentid?: string | number; // 父组织ID(新增子组织时必传)
     type?: 'children' | 'parent'; // 组织类型(子组织或根组织)
   }
-
-  // 保存弹窗回调
+   // 保存弹窗回调
   const confirmAddSafetySystemCallback = async (formData: SafetySystemFormData) => {
     try {
       if (!formData.value?.trim()) {
         ElMessage.warning('请输入有效的组织名称!');
         return;
       }
+      // 新增时,传orgName(组织名称)、parentid(父组织ID)
+      // 编辑时,传当前ID和orgName
       const requestData = {
         orgName: formData.value.trim(),
         id: formData.action === 'edit' ? formData.orgId : undefined,
+        // 第一级不需要传parentid
         parentid: formData.action === 'add' ? formData.parentid : undefined,
       };
-      // console.log(formData, 'formData')
+      console.log(formData, '参数--formData')
       if (formData.action === 'add') {
         if (formData.type === 'children' && formData.orgId) {
           requestData.parentid = formData.orgId;
@@ -339,31 +461,7 @@ const position = ref('left')
       ElMessage.error(formData.action === 'add' ? '新增组织失败!' : '编辑组织失败!');
     }
   };
-  // 二级新增
-  const handleCreateSafetySystem = async (type, value) => {
-    addSafetyOrganizationSystemFormData.value = {
-      type:'children',
-      action: 'add',
-      orgName: value.orgName,
-      orgId: value.orgId,
-    };
-    addSafetySystemVisible.value = true;
-    // 打开某一个
-    // activeName.value = value.orgId;
-  };
-  // 编辑
-  const handleEditSafetySystem = (type, value, parentid) => {
-    // console.log(value)
-    addSafetySystemVisible.value = true;
-    addSafetyOrganizationSystemFormData.value = {
-      type,
-      action: 'edit',
-      orgName: value.orgName,
-      orgId: value.orgId,
-      parentid,
-    };
-  };
-  // 删除
+    // 删除
   const handleDelSafetySystem = async (type, value) => {
     // console.log('删除', type, value)
     ElMessageBox.confirm('确认删除该组织吗?', '警告', { type: 'warning' }).then(async () => {
@@ -374,7 +472,7 @@ const position = ref('left')
         }
         await deleteSafetySystem(value.orgId);
         ElMessage.success('删除成功');
-        // 刷新列表
+        // 刷新组织列表
         fetchSafetyOrganizationTeamList();
         handleReset();
       } catch (error) {
@@ -382,14 +480,16 @@ const position = ref('left')
       }
     });
   };
-  // 查询
-  const querySafetyTeamData = (value) => {
-    // console.log('查询', value);
-    tableQuery.queryParam.classifyName = value.orgId;
-    safetyOrgDetail(value.orgId)
-    getTableData();
-  };
 
+  
+  // 定义组织数据类型
+  interface SafetySystemFormData {
+    value: string; // 输入的组织名称
+    action: 'add' | 'edit'; // 操作类型:新增或编辑
+    orgId?: string | number; // 组织ID(编辑时必传)
+    parentid?: string | number; // 父组织ID(新增子组织时必传)
+    type?: 'children' | 'parent'; // 组织类型(子组织或根组织)
+  }
 
   // 时间查询
   const onchangeDateRange = () => {
@@ -489,10 +589,11 @@ const position = ref('left')
       },
     });
   };
-  onMounted(() => {
-    fetchSafetyOrganizationTeamList();
-    // 默认读取上个选中架构组织的员工数据
-    const orgId = route.query.id as string;
+  onMounted(async () => {
+    fetchSafetyOrganizationTeamList()
+    // 默认读取第一个架构组织的员工数据
+    const res = await getSafetySystemList();
+    const orgId = res[0]?.orgId;
     tableQuery.queryParam.classifyName = orgId || undefined
     getTableData();
     if(orgId){
@@ -514,6 +615,9 @@ const position = ref('left')
     width: 0;
     min-width: 0;
   }
+   .mb-4{
+    margin-bottom: 16px;
+ }
   .nav {
     flex: 0 0 300px;
     margin-right: 15px;
@@ -569,4 +673,14 @@ const position = ref('left')
   .label-title{
     margin-bottom:16px;
   }
+  .chart {
+    height:260px;
+    background-color: #f1f7ff;
+    border-radius: 4px;
+    overflow: hidden;
+  }
+  .content {
+    height: calc(100% - 260px - 32px);
+    overflow-y: auto;
+  }
 </style>