Bootstrap

树形数据增删改查

功能描述:

  1. 默认展示所有项目
  2. 点击项目展示当前项目下的所有区域
  3. 点击区域展示当前区域下的所有工位
  4. 以上以树形图格式展示
  5. 项目,区域,和工位都可进行增加 修改 和删除,每个图标hover时显示对应提示信息
  6. 项目,区域,工位可导入数据,提供下载模板功能
  7. 部门配置单独列出,展示所有部门列表,部门可进行增加,修改和删除

效果示意图
在这里插入图片描述

所有代码:

<template>
   <el-row :gutter="15" justify="center" style="height:100%;">
     <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
      <el-main  style="width:100%;margin:0 auto;position:relative; height:100%;padding:0;background:#fff;padding:10px;">
        <h1 style="text-align:center;margin-top:10px;">项目区域配置</h1>
        <!-- <a style="position:absolute;left:5px;top:8px;color:#3388cc;font-size:12px; text-decoration:underline;" target="_blank" href="#/questionCommit"> <el-icon><Back /></el-icon> 问题提交</a>
        <a style="position:absolute;right:5px;top:8px;color:#3388cc;font-size:12px; text-decoration:underline;" target="_blank" href="#/questionList"> 问题列表 <el-icon><Right /></el-icon></a> -->

  <el-tabs v-model="activeName" class="demo-tabs" >
    <el-tab-pane label="项目配置" name="first">
      <div>
      <el-button type="primary" @click="addProject">添加项目</el-button>

      <el-upload
            style="float:right;"
            ref="uploadRef"
            :on-change="importProject"
            class="upload-demo"
            :limit="1"
            accept=".xlsx"
            :auto-upload="false"
            action=""
          >
            <el-button type="primary">导入数据</el-button>
          </el-upload>

          <el-button type="primary" @click="downloadXLSX"   style="float:right;margin-right:10px">下载模板</el-button>
      <ul>
        <li v-for="project in projects" :key="project.projectId">
          <el-collapse @change="handleChangeProject(project,project.projectId)">
            <el-collapse-item >
              <template #title>
                <span v-if="project.editing">
                  <input v-model="project.projectName"  />
                </span>
                <b v-else> {{ project.projectName }}</b>
                &nbsp;&nbsp;
                <el-tooltip
                  class="box-item"
                  effect="dark"
                  :content="project.editing?'保存项目名称':'编辑项目名称'"
                  placement="top-start"
                >
                <el-icon @click.stop="toggleEditProject(project)" style="color:#3388cc;cursor:pointer;">
                <SuccessFilled v-if="project.editing" @click.stop="saveProject(project)"/>
                <Edit v-else /></el-icon>
                </el-tooltip>
                &nbsp;&nbsp;
                <el-tooltip
                  class="box-item"
                  effect="dark"
                  content="删除当前项目"
                  placement="top-start"
                >
                <el-icon @click.stop="confirmRemoveProject(project)" style="color:red;cursor:pointer;"><Delete/></el-icon>
                </el-tooltip>
                &nbsp;&nbsp;
                <el-tooltip
                  class="box-item"
                  effect="dark"
                  content="当前项目下添加区域"
                  placement="top-start"
                >
                    <el-icon @click.stop="addArea(project)" style="cursor:pointer;"><CirclePlusFilled /></el-icon>
                </el-tooltip>

              </template>
              <div>
                <ul>
                  <li v-for="area in project.areas" :key="area.regionId">
                    <el-collapse @change="handleChangeRegion(area,area.regionId)">
                      <el-collapse-item>
                        <template #title>
                        <span v-if="area.editing">
                          <input v-model="area.regionName" />
                        </span>
                        <b v-else>
                          {{ area.regionName }}
                        </b>
                        &nbsp;&nbsp;
                        <el-tooltip
                          class="box-item"
                          effect="dark"
                          :content="area.editing?'保存区域名称':'编辑区域名称'"
                          placement="top-start"
                        >
                        <el-icon @click.stop="toggleEditArea(area)" style="color:#3388cc;cursor:pointer;">
                                  <SuccessFilled v-if="area.editing"  @click.stop="saveArea(project,area)"/>
                                  <Edit v-else /></el-icon>
                        </el-tooltip>
                          &nbsp;&nbsp;
                          <el-tooltip
                            class="box-item"
                            effect="dark"
                            content="删除当前区域"
                            placement="top-start"
                          >
                          <el-icon @click.stop="confirmRemoveArea(project, area)" style="color:red;cursor:pointer;"><Delete/></el-icon>
                          </el-tooltip>
                          &nbsp;&nbsp;
                          <el-tooltip
                            class="box-item"
                            effect="dark"
                            content="当前区域下添加工位"
                            placement="top-start"
                          >
                          <el-icon @click.stop="addStation(project, area)" style="cursor:pointer;"><CirclePlusFilled /></el-icon>
                          </el-tooltip>


                      </template>
                        <div>
                          <ul>
                            <li v-for="station in area.stations" :key="station.stationId" >
                              <div>
                                <span v-if="station.editing">
                                  <input v-model="station.stationName"  />
                                </span>
                                <b v-else>
                                  {{ station.stationName }}
                                </b>
                                &nbsp;&nbsp;
                                <el-tooltip
                                  class="box-item"
                                  effect="dark"
                                  :content="station.editing?'保存工位名称':'编辑工位名称'"
                                  placement="top-start"
                                >
                                <el-icon @click.stop="toggleEditStation(station)" style="color:#3388cc;cursor:pointer;">
                                <SuccessFilled v-if="station.editing" @click.stop="saveStation(project, area, station)" />
                                 <Edit v-else /></el-icon>
                                </el-tooltip>

                                &nbsp;&nbsp;
                                <el-tooltip
                                  class="box-item"
                                  effect="dark"
                                  content="删除当前工位"
                                  placement="top-start"
                                >
                                <el-icon @click.stop="confirmRemoveStation(project, area, station)" style="color:red;cursor:pointer;"><Delete/></el-icon>
                                </el-tooltip>

                              </div>
                            </li>
                          </ul>
                        </div>
                      </el-collapse-item>
                    </el-collapse>
                  </li>
                </ul>
              </div>
            </el-collapse-item>
          </el-collapse>
        </li>
      </ul>

    </div>
    </el-tab-pane>
    <el-tab-pane label="部门配置" name="second">
      <el-button type="primary" @click="addDepartmentName">添加部门</el-button>
      <ul>
        <li v-for="department in departmentNameList" :key="department.id">
          <div  style="height:40px;line-height:40px;border-bottom:1px solid #ddd;">
            <span v-if="department.editing">
              <input v-model="department.departmentName" />
            </span>
            <span v-else>
              {{ department.departmentName }}
            </span>
            &nbsp;&nbsp;
            <el-tooltip
              class="box-item"
              effect="dark"
              :content="department.editing?'保存部门名称':'编辑部门名称'"
              placement="top-start"
            >
            <el-icon @click="toggleEditDepartment(department)" style="color:#3388cc;cursor:pointer;">
            <SuccessFilled v-if="department.editing"  @click="saveDepartment(department)"/>
              <Edit v-else /></el-icon>
            </el-tooltip>

            &nbsp;&nbsp;
            <el-tooltip
              class="box-item"
              effect="dark"
              content="删除当前部门"
              placement="top-start"
            >
            <el-icon @click="confirmRemoveDepartment(department)" style="color:red;cursor:pointer;"><Delete/></el-icon>
            </el-tooltip>

          </div>
        </li>
      </ul>
    </el-tab-pane>
  </el-tabs>
  <el-dialog v-model="showConfirmDialog" title="确认删除" @close="showConfirmDialog = false">
      <span v-if="itemToDelete" style="margin:20px auto">
        确定要删除 {{ itemToDelete.type }}{{ itemToDelete.name }} 吗?
      </span>
      <el-button type="danger" @click="deleteItem">确认删除</el-button>
    </el-dialog>
      </el-main>
     </el-col>
     </el-row>

</template>
<script lang="ts" setup>
import { ref } from 'vue'
import * as XLSX from 'xlsx';
import type { TabsPaneContext} from 'element-plus'
import {insertDepartment,upload,deleteDeptById,deleteProjectById,deleteAreaById,deleteStationById,updateDepartmentById,insertOrUpdateArea,insertProject,insertOrUpdateStation,queryDepartmentName,queryProject,queryRegionByProject,queryStationName} from '@/api/user'
import { ElMessage } from 'element-plus'
let showConfirmDialog = ref(false)
let itemToDelete = ref(null)
let projects = ref([
        {
          projectId: 1,
          projectName: '项目1',
          areas: [
            {
              regionId: 11,
              regionName: '区域1',
              projectId: 1,
              stations: [{
                stationId:118,
                stationName:"H005 机壳上线",
                regionId:120}
              ],
            },
          ],
        },
      ])
let departmentNameList = ref([]);
const activeName = ref('first')

let downloadXLSX = ()=>{
      // 创建一个 XLSX 工作簿
      const wb = XLSX.utils.book_new();
      // 创建一个工作表
      const ws = XLSX.utils.json_to_sheet([
        // 在这里定义模板的列和初始数据
        { '项目名称':'','区域':'','工位名称':'' },
        // 您可以在这里添加更多的模板数据行
      ]);
      // 向工作簿添加工作表
      XLSX.utils.book_append_sheet(wb, ws, '模板数据');

      // 生成 XLSX 文件
      XLSX.writeFile(wb, '模板数据.xlsx');
    }
let importProject : UploadProps['onChange'] = (uploadFile, uploadFiles) => {
  console.log(uploadFile);
  let formData = new FormData();
  formData.append('file', uploadFile.raw)
  upload(formData).then((data)=>{
  if(data.status == 200){
    ElMessage({
        message: '导入成功',
        type: 'success',
      })
    }
})}

let toggleEditProject = (project) => {
  // 切换项目编辑状态
  project.editing = !project.editing
}
let toggleEditArea = (area) => {
  // 切换区域编辑状态
  area.editing = !area.editing
}
let toggleEditStation = (station) => {
  // 切换工位编辑状态
  station.editing = !station.editing
}
let toggleEditDepartment = (department) => {
  // 切换部门编辑状态
  department.editing = !department.editing
}

const getList = () => {
//获取所有部门列表
queryDepartmentName().then((data)=>{
if(data.status == 200){
  departmentNameList.value = data.data;
}
})
//获取所有项目列表
queryProject().then((data)=>{
if(data.status == 200){
  projects.value = data.data;
  console.log(projects)
}
})
}
//点击项目获取项目下的区域
let handleChangeProject = (project,id)=>{
  let formData = new FormData();
formData.append('projectId', id);
queryRegionByProject(formData).then((data)=>{
if(data.status == 200){
   project.areas = data.data;
}
})
}
//点击区域获取区域下面的工位
let handleChangeRegion = (region,id)=>{
  let formData1 = new FormData();
    formData1.append('areaId', id);
    queryStationName(formData1).then((data)=>{
    if(data.status == 200){
       region.stations = data.data;
    }
})
}

//添加项目
let addProject = () => {
  let formData = new FormData();
  let num =  Math.floor(Math.random() * 1000)
  formData.append('projectName', '新项目'+num);
  insertProject(formData).then((data)=>{
    if(data.status == 200){
      const newProject = {
        projectId: Math.floor(data.data),
        projectName: '新项目'+num,
        areas: [],
      }
      projects.value.push(newProject)
      ElMessage({
        message: '添加项目成功,名为 新项目'+num+',可修改',
        type: 'success',
      })
    }else{
      ElMessage({
        message: '添加项目失败',
        type: 'error',
      })
    }
  })

}
//添加区域
let addArea = (project) => {
  let formData = new FormData();
  formData.append('projectId', project.projectId);
  let num1 =  Math.floor(Math.random() * 1000)
  formData.append('regionName', '新区域'+num1);
  insertOrUpdateArea(formData).then((data)=>{
    if(data.status == 200){
      const newArea = {
        regionId: Math.floor(data.data),
        regionName: '新区域'+num1,
        projectId:project.projectId,
        stations: [],
      }
      project.areas.push(newArea)
      ElMessage({
        message: '添加区域成功,名为 新区域'+num1+',可修改',
        type: 'success',
      })
    }else{
      ElMessage({
        message: '添加区域失败',
        type: 'error',
      })
    }
  })
}
// 添加工位
let addStation = (project, area) => {
  let formData = new FormData();
  formData.append('regionId', area.regionId);//
  let num2 =  Math.floor(Math.random() * 1000)
  formData.append('stationName', '新工位'+num2);
  insertOrUpdateStation(formData).then((data)=>{
    if(data.status == 200){
      const newStation = {
        stationId: Math.floor(data.data),
        stationName:'新工位'+num2,
        regionId:area.regionId
      }
      area.stations.push(newStation)
      ElMessage({
        message: '添加工位成功,名为 新工位'+num2+',可修改',
        type: 'success',
      })
    }else{
      ElMessage({
        message: '添加工位失败',
        type: 'error',
      })
    }
  })
}

//添加部门
let addDepartmentName = ()=>{
  let formData = new FormData();
  let num3 =  Math.floor(Math.random() * 1000)
  formData.append('departmentName', '新部门'+num3);
  insertDepartment(formData).then((data)=>{
    if(data.status == 200){
      const newDepartmentName = {
      id: Math.floor(data.data),
      departmentName: '新部门'+num3,
      }
      departmentNameList.value.push(newDepartmentName)
      ElMessage({
        message: '添加部门成功,名为 新部门'+num3+',可修改',
        type: 'success',
      })
    }else{
      ElMessage({
        message: '添加部门失败',
        type: 'error',
      })
    }
  })

}


 // 保存项目编辑
let saveProject = (project) => {
  let formData = new FormData();
  formData.append('projectId', project.projectId);
  formData.append('projectName', project.projectName);
  insertProject(formData).then((data)=>{
    if(data.status == 200){
      project.editing = false
      ElMessage({
        message: '修改项目名成功',
        type: 'success',
      })
    }else{
      ElMessage({
        message: '修改项目失败',
        type: 'error',
      })
    }
  })
}
 // 保存区域编辑
let saveArea = (project, area) => {
  let formData = new FormData();
  formData.append('projectId', project.projectId);
  formData.append('regionId', area.regionId);
  formData.append('regionName', area.regionName);
  insertOrUpdateArea(formData).then((data)=>{
    if(data.status == 200){
      area.editing = false
      ElMessage({
        message: '修改区域名成功',
        type: 'success',
      })
    }else{
      ElMessage({
        message: '修改区域名失败',
        type: 'error',
      })
    }
  })

}
 // 保存工位编辑
let saveStation = (project, area, station) => {
  let formData = new FormData();
  formData.append('regionId', area.regionId);
  formData.append('stationName', station.stationName);
  formData.append('stationId', station.stationId);
  insertOrUpdateStation(formData).then((data)=>{
    if(data.status == 200){
      station.editing = false
      ElMessage({
        message: '修改工位名成功',
        type: 'success',
      })
    }else{
      ElMessage({
        message: '修改工位名失败',
        type: 'error',
      })
    }
  })
}
// 保存部门编辑
let saveDepartment = (department) => {
  let formData = new FormData();
  formData.append('id', department.id);
  formData.append('departmentName',department.departmentName);
  insertDepartment(formData).then((data)=>{
    if(data.status == 200){
      department.editing = false
      ElMessage({
        message: '修改部门名成功',
        type: 'success',
      })
    }else{
      ElMessage({
        message: '修改部门名失败',
        type: 'error',
      })
    }
  })
}

//删除项目
let confirmRemoveProject = (project) => {
  itemToDelete.value = { type: '项目',name: project.projectName,project,data: { id: project.projectId } }
  showConfirmDialog.value = true
}
//删除区域
let confirmRemoveArea = (project, area) => {
  itemToDelete.value = { type: '区域',  name: area.regionName,project,area,data: { id: area.regionId } }
  showConfirmDialog.value = true
}
//删除工位
let confirmRemoveStation = (project, area, station) => {
  itemToDelete.value = { type: '工位', name: station.stationName,project,area, station, data: {  id: station.stationId } }
  showConfirmDialog.value = true
}
//删除部门
let confirmRemoveDepartment = (department) => {
  itemToDelete.value = { type: '部门', name: department.departmentName,department,data: { id: department.id } }
  showConfirmDialog.value = true
}


//确认删除
let deleteItem = () => {
  if (itemToDelete.value) {
    if (itemToDelete.value.type === '项目') {
      // 执行删除项目的逻辑
      let json ={'projectId':itemToDelete.value.data.id}
      deleteProjectById(json).then((data)=>{
      if(data.status == 200){
          const projectIdToDelete = itemToDelete.value.data.id;
          const indexToDelete = projects.value.findIndex(
            (project) => project.projectId === projectIdToDelete
          );
          if (indexToDelete !== -1) {
            projects.value.splice(indexToDelete, 1);
          }
        ElMessage({
            message: '删除项目成功',
            type: 'success',
          })

      }
      })
    } else if (itemToDelete.value.type === '区域') {
      // 执行删除区域的逻辑
      let json ={'areaId':itemToDelete.value.data.id}
      deleteAreaById(json).then((data)=>{
      if(data.status == 200){
          // 从项目的区域列表中删除已删除的区域
          const project = itemToDelete.value.project;
          const area = itemToDelete.value.area;
          const areaIdToDelete = itemToDelete.value.data.id;

          // 查找项目并从它的区域列表中删除区域
          if (project) {
            const projectIndex = projects.value.findIndex((p) => p === project);
            if (projectIndex !== -1 && area) {
              const areaIndex = project.areas.findIndex((a) => a === area);
              if (areaIndex !== -1) {
                project.areas.splice(areaIndex, 1);
              }
            }
          }
            ElMessage({
                message: '删除区域成功',
                type: 'success',
              })
          }
          })
    } else if (itemToDelete.value.type === '工位') {
      // 执行删除工位的逻辑
      let json ={'stationId':itemToDelete.value.data.id}
      deleteStationById(json).then((data)=>{
      if(data.status == 200){
         // 从项目的区域的工位列表中删除已删除的工位
       // 从项目的区域的工位列表中删除已删除的工位
          const project = itemToDelete.value.project;
          const area = itemToDelete.value.area;
          const stationIdToDelete = itemToDelete.value.data.id;

          // 查找项目、区域,并从它的工位列表中删除工位
          if (project && area) {
            const projectIndex = projects.value.findIndex((p) => p === project);
            if (projectIndex !== -1) {
              const areaIndex = project.areas.findIndex((a) => a === area);
              if (areaIndex !== -1) {
                const stationIndex = area.stations.findIndex((s) => s.stationId === stationIdToDelete);
                if (stationIndex !== -1) {
                  area.stations.splice(stationIndex, 1);
                }
              }
            }
          }
        ElMessage({
            message: '删除工位成功',
            type: 'success',
          })
      }
      })
    } else if (itemToDelete.value.type === '部门') {
      // 执行删除部门的逻辑
      let json ={'id':itemToDelete.value.data.id}
      deleteDeptById(json).then((data)=>{
      if(data.status == 200){
          // 从部门列表中删除已删除的部门
          const departmentIdToDelete = itemToDelete.value.data.id;
          const indexToDelete = departmentNameList.value.findIndex(
            (department) => department.id === departmentIdToDelete
          );
          if (indexToDelete !== -1) {
            departmentNameList.value.splice(indexToDelete, 1);
          }

        ElMessage({
            message: '删除部门成功',
            type: 'success',
          })
      }
      })
    }
    showConfirmDialog.value = false
  }
}

onMounted(() => {
   getList();
})
</script>
<style>
.demo-tabs > .el-tabs__content {
  padding: 32px;
  color: #6b778c;

  font-weight: 600;
}

  body{
    background:#ccc;
  }
  </style>

提示
当前页面所有请求接口请根据自己项目实际情况修改
当前代码版本基于 vue3 elementplus
下载模板需要安装xlsx插件

;