ソースを参照

组织架构-树形控件

yangyuxuan 5 ヶ月 前
コミット
6ca7629cdf

+ 9 - 0
src/api/tree.ts

@@ -0,0 +1,9 @@
+import request from "@/utils/request";
+
+// 获取单位地址
+export function getTree(id) {
+  return request({
+    url: "/api/system/area/tree/" + id,
+    method: "get"
+  });
+}

BIN
src/assets/images/threePreventionResponsiblePerson/archNotSel.png


BIN
src/assets/images/threePreventionResponsiblePerson/archSel.png


BIN
src/assets/images/threePreventionResponsiblePerson/informNotSel.png


BIN
src/assets/images/threePreventionResponsiblePerson/informSel.png


BIN
src/assets/images/threePreventionResponsiblePerson/offlineUsers.png


BIN
src/assets/images/threePreventionResponsiblePerson/onlineUsers.png


+ 0 - 0
src/assets/images/tempImage/weizhi.png → src/assets/images/threePreventionResponsiblePerson/position.png


+ 45 - 404
src/views/threePreventionResponsiblePerson/index.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="page-head">
+  <div v-show="!isShowStructure" class="page-head">
     <van-search
       v-model="keywords"
       placeholder="请输入搜索关键词"
@@ -10,7 +10,14 @@
     <div class="select-box">
       <div class="adress-box" @click="showStructure">
         <div class="blue-rectangle" />
-        <div style="margin-left: 5px">{{upOneLevel}}>{{ adressContent }}</div>
+        <div class="block1" v-if="!!requestParameters.checkedId">
+          <div>{{ upOneLevel }}</div>
+          <div style="color: #1d92ff">>{{ adressContent }}</div>
+        </div>
+        <div class="block1" v-else>
+          <div>广东省</div>
+          <div style="color: #1d92ff">>茂名市</div>
+        </div>
       </div>
       <div>
         <van-field
@@ -39,13 +46,7 @@
     </div>
     <hr style="color: #f9f9f9" />
   </div>
-  <div
-    style="
-      margin-top: 90px;
-      height: calc(100vh - 55px - 90px);
-      overflow: scroll;
-    "
-  >
+  <div v-show="!isShowStructure" style="height: calc(100vh - 154px);overflow: scroll;">
     <van-list
       v-model:loading="loading"
       :finished="finished"
@@ -55,7 +56,10 @@
       <div v-for="item in persons" :key="item.id">
         <div class="person-box" @click="showPersonalInformation(item)">
           <div class="circle">
-            <img :src="item.profile_picture" alt="" />
+            <img
+              :src="item.state === false ? offlineUser : onlineUser"
+              alt=""
+            />
           </div>
           <div class="information-card">
             <div class="one">
@@ -72,83 +76,22 @@
             </div>
           </div>
         </div>
+        <div class="link-top" />
       </div>
     </van-list>
   </div>
-  <div>
-    <van-overlay :show="isShowStructure">
-      <div class="block1">
-        <van-search
-          v-model="keywords"
-          placeholder="请输入关键字"
-          :left-icon="searchImg"
-          :right-icon="closeImg"
-          :clearable="false"
-          @search="onSearchKeyword"
-          @click-right-icon.stop="onSearchCancel"
-        />
-        <div class="head-card">
-          <div class="structure-head">
-            <div class="blue-rectangle" />
-            <div style="margin-top: 5px; margin-left: 5px">组织架构</div>
-          </div>
-          <div style="color: #b7c0c4; padding: 8px 13px; font-size: 13px">
-            [总人数]
-          </div>
-        </div>
-        <hr />
-        <div style="margin-top: 1px">
-          <el-tree
-            :data="treeData"
-            :props="defaultProps"
-            default-expand-all
-            style="
-              height: calc(-145px - 70px + 100vh);
-              overflow: scroll;
-              margin-left: 10px;
-            "
-          >
-            <template #default="{ node, data }">
-              <div v-if="!data.isShowSelect" class="custom-tree-node">
-                {{ node.label }}
-              </div>
-              <div
-                v-else
-                class="custom-tree-node"
-                @click="handleCheckChange(data)"
-              >
-                <img :src="adressImage" class="addressImage" />
-                {{ node.label }}
-              </div>
-              <span>
-                <a
-                  style="color: #d6d6d7; margin-right: 12px"
-                  @click="append(data)"
-                >
-                  [ {{ data.personSum }} ]
-                </a>
-              </span>
-            </template>
-          </el-tree>
-        </div>
-        <div class="footer">
-          <div class="cancel-btn" @click="handleCancel">组织架构</div>
-          <div class="confirm-btn" @click="handleToPersonInfo">个人信息</div>
-        </div>
-      </div>
-    </van-overlay>
-  </div>
+  <organizationalStructure v-if="isShowStructure" v-model:isShowStructure="isShowStructure" @confirm="handleSelect" />
 </template>
 
 <script setup lang="ts">
 import profile from "@/assets/images/tempImage/用户.png";
-import adressImage from "@/assets/images/tempImage/weizhi.png";
+import offlineUser from "@/assets/images/threePreventionResponsiblePerson/offlineUsers.png";
+import onlineUser from "@/assets/images/threePreventionResponsiblePerson/onlineUsers.png";
 import { getDicts } from "@/api/system/dict/data";
 import { getEventList } from "@/api/event";
 import searchImg from "@/assets/images/search.png";
 import closeImg from "@/assets/images/close.png";
-import { ElTree, ElCheckboxGroup, ElCheckbox } from "element-plus";
-import { showConfirmDialog, showFailToast, showToast } from "vant";
+import OrganizationalStructure from "@/views/threePreventionResponsiblePerson/organizationalStructure.vue";
 
 const router = useRouter();
 const keywords = ref("");
@@ -173,7 +116,8 @@ const requestParameters = ref({
   type_content: "",
   page: 1,
   page_size: 10,
-  keyword: keywords
+  keyword: keywords,
+  checkedId: ""
 });
 const persons = ref([]);
 const onLoad = () => {
@@ -308,286 +252,29 @@ const onSearch = keywords => {
 const showPersonalInformation = item => {
   router.push({ name: "PersonInformation", query: { id: item.id } });
 };
-
 let keyword = ref("");
-let treeData = ref([
-  {
-    id: 1,
-    label: "茂南区",
-    personSum: 34643,
-    isShowSelect: false,
-    children: [
-      {
-        id: 2,
-        label: "茂南区政府",
-        personSum: 343,
-        isShowSelect: false,
-        parentLabel: "茂南区",
-        children: [
-          {
-            id: 3,
-            label: "应急管理局",
-            personSum: 5687,
-            isShowSelect: false,
-            parentLabel: "茂南区政府",
-            children: [
-              {
-                id: 4,
-                label: "应急管理局2",
-                isShowSelect: true,
-                parentLabel: "应急管理局",
-                personSum: 5687
-              },
-              {
-                id: 30,
-                label: "茂南区应急管理局3",
-                isShowSelect: true,
-                parentLabel: "茂南区应急管理局",
-                personSum: 5687
-              }
-            ]
-          }
-        ]
-      }
-    ]
-  },
-  {
-    id: 5,
-    deptType: true,
-    label: "茂南区",
-    personSum: 34643,
-    isShowSelect: false,
-    children: [
-      {
-        id: 6,
-        deptType: true,
-        label: "茂南区政府",
-        personSum: 343,
-        isShowSelect: false,
-        children: [
-          {
-            id: 7,
-            deptType: true,
-            label: "茂南区应急管理局",
-            personSum: 5687,
-            isShowSelect: false,
-            children: [
-              {
-                id: 8,
-                deptType: true,
-                label: "茂南区应急管理局",
-                isShowSelect: true,
-                personSum: 5687
-              }
-            ]
-          }
-        ]
-      }
-    ]
-  },
-  {
-    id: 9,
-    deptType: true,
-    label: "茂南区",
-    personSum: 34643,
-    isShowSelect: false,
-    children: [
-      {
-        id: 10,
-        deptType: true,
-        label: "茂南区政府",
-        personSum: 343,
-        isShowSelect: false,
-        children: [
-          {
-            id: 11,
-            deptType: true,
-            label: "茂南区应急管理局",
-            personSum: 5687,
-            isShowSelect: false,
-            children: [
-              {
-                id: 12,
-                deptType: true,
-                label: "茂南区应急管理局",
-                isShowSelect: true,
-                personSum: 5687
-              }
-            ]
-          }
-        ]
-      }
-    ]
-  },
-  {
-    id: 13,
-    deptType: true,
-    label: "茂南区",
-    personSum: 34643,
-    isShowSelect: false,
-    children: [
-      {
-        id: 14,
-        deptType: true,
-        label: "茂南区政府",
-        personSum: 343,
-        isShowSelect: false,
-        children: [
-          {
-            id: 15,
-            deptType: true,
-            label: "茂南区应急管理局",
-            personSum: 5687,
-            isShowSelect: false,
-            children: [
-              {
-                id: 16,
-                deptType: true,
-                label: "茂南区应急管理局",
-                isShowSelect: true,
-                personSum: 5687
-              }
-            ]
-          }
-        ]
-      }
-    ]
-  },
-  {
-    id: 17,
-    deptType: true,
-    label: "茂南区",
-    personSum: 34643,
-    isShowSelect: false,
-    children: [
-      {
-        id: 18,
-        deptType: true,
-        label: "茂南区政府",
-        personSum: 343,
-        isShowSelect: false,
-        children: [
-          {
-            id: 19,
-            deptType: true,
-            label: "茂南区应急管理局",
-            personSum: 5687,
-            isShowSelect: false,
-            children: [
-              {
-                id: 20,
-                deptType: true,
-                label: "茂南区应急管理局",
-                isShowSelect: true,
-                personSum: 5687
-              }
-            ]
-          }
-        ]
-      }
-    ]
-  },
-  {
-    id: 21,
-    deptType: true,
-    label: "茂南区",
-    personSum: 34643,
-    isShowSelect: false,
-    children: [
-      {
-        id: 22,
-        deptType: true,
-        label: "茂南区政府",
-        personSum: 343,
-        isShowSelect: false,
-        children: [
-          {
-            id: 23,
-            deptType: true,
-            label: "茂南区应急管理局",
-            personSum: 5687,
-            isShowSelect: false,
-            children: [
-              {
-                id: 24,
-                deptType: true,
-                label: "茂南区应急管理局",
-                isShowSelect: true,
-                personSum: 5687
-              }
-            ]
-          }
-        ]
-      }
-    ]
-  },
-  {
-    id: 25,
-    deptType: true,
-    label: "茂南区",
-    personSum: 34643,
-    isShowSelect: false,
-    children: [
-      {
-        id: 26,
-        deptType: true,
-        label: "茂南区政府",
-        personSum: 343,
-        isShowSelect: false,
-        children: [
-          {
-            id: 27,
-            deptType: true,
-            label: "茂南区应急管理局",
-            personSum: 5687,
-            isShowSelect: false,
-            children: [
-              {
-                id: 28,
-                deptType: true,
-                label: "茂南区应急管理局",
-                isShowSelect: true,
-                personSum: 5687
-              }
-            ]
-          }
-        ]
-      }
-    ]
-  }
-]);
 let treeRef = ref();
 let checkData = ref([]);
 const isShowStructure = ref(false);
 const showStructure = () => {
   isShowStructure.value = true;
 };
-const onSearchKeyword = () => {};
-const onSearchCancel = () => {};
-const handleCancel = () => {
-  isShowStructure.value = false;
-};
+
 const adressContent = ref();
 const upOneLevel = ref();
-let defaultProps = reactive({
-  children: "children",
-  label: "label",
-  personSum: "personSum"
-});
+
 const filterNode = (value, data) => {
   if (!value) return true;
   return data.label.indexOf(value) !== -1;
 };
 let selectedTreeId = ref([]);
-const handleCheckChange = data => {
-    adressContent.value = data.label;
-    upOneLevel.value = data.parentLabel;
-    isShowStructure.value = false;
+const handleSelect = (data) => {
+  adressContent.value = data.label;
+  upOneLevel.value = data.value;
+  requestParameters.value.checkedId = data.id;
 };
 
-const handleToPersonInfo = () => {
-  router.push({ name: 'EditPersonInformation'});
-}
+
 </script>
 
 <style scoped lang="scss">
@@ -625,6 +312,7 @@ const handleToPersonInfo = () => {
 .person-box {
   display: flex;
   flex-direction: row;
+  margin-left: 10px;
 }
 .information-card {
   display: flex;
@@ -637,6 +325,7 @@ const handleToPersonInfo = () => {
   font-size: 13px;
   color: #8d9bc8;
   margin-left: 5px;
+  border-radius: 2px;
   &:nth-child(1) {
     margin-left: 0;
   }
@@ -661,7 +350,8 @@ const handleToPersonInfo = () => {
   padding: 0px 10px;
   height: 15px;
   padding-bottom: 18px;
-  border-radius: 4px;
+  border-radius: 2px;
+  color: #ffffff;
 }
 .isOnline {
   background-color: limegreen;
@@ -677,11 +367,7 @@ const handleToPersonInfo = () => {
   height: 100%;
   background-color: #f2f2f2;
 }
-.block1 {
-  width: 100%;
-  height: 100%;
-  background-color: #ffffff;
-}
+
 .information-box {
   display: flex;
   flex-direction: row;
@@ -713,17 +399,8 @@ const handleToPersonInfo = () => {
   text-align-last: justify;
 }
 .page-head {
-  position: fixed;
-  top: 0;
   width: 100%;
 }
-.structure-head {
-  display: flex;
-  background-color: #ffffff;
-  padding-left: 20px;
-  padding-bottom: 5px;
-  align-items: center;
-}
 .blue-rectangle {
   width: 6px;
   height: 20px;
@@ -731,61 +408,25 @@ const handleToPersonInfo = () => {
   border-radius: 0 3px 0 0;
   margin-left: -10px;
 }
-.head-card {
+
+.adress-box {
   display: flex;
   flex-direction: row;
-  justify-content: space-between;
-  background-color: white;
+  padding-top: 10px;
+  width: 50%;
+  margin-left: 20px;
 }
-.footer {
-  position: absolute;
-  z-index: 9999;
-  bottom: 0;
-  left: 0;
-  width: 100%;
-  height: 70px;
-  background: #ffffff;
-  display: flex;
-  justify-content: center;
-  align-items: center;
-  margin-bottom: 50px;
-  .cancel-btn {
-    width: 90px;
-    height: 40px;
-    border: 1px solid #d1d1d1;
-    border-radius: 2px;
-    font-size: 16px;
-    color: #b3b3b3;
-    display: flex;
-    justify-content: center;
-    align-items: center;
-  }
-  .confirm-btn {
-    width: 90px;
-    height: 40px;
-    background: #2c81ff;
-    border-radius: 2px;
-    font-size: 16px;
-    color: #ffffff;
-    display: flex;
-    justify-content: center;
-    align-items: center;
-    margin-left: 80px;
-  }
+.link-top {
+  height: 0.5px;
+  border-top: solid #fafafa 1px;
 }
-.custom-tree-node {
+.block2 {
   display: flex;
-  width: 100%;
-  margin-right: 12px;
-}
-.addressImage {
-  height: 15px;
+  flex-direction: column;
 }
-.adress-box {
+.block1 {
   display: flex;
   flex-direction: row;
-  padding-top: 10px;
-  width: 50%;
-  margin-left: 20px;
+  margin-left: 5px;
 }
 </style>

+ 226 - 0
src/views/threePreventionResponsiblePerson/organizationalStructure.vue

@@ -0,0 +1,226 @@
+<template>
+  <div>
+    <div class="block1">
+      <van-search
+        v-model="keywords"
+        placeholder="请输入关键字"
+        :left-icon="searchImg"
+        :right-icon="closeImg"
+        :clearable="false"
+        @search="onSearchKeyword"
+        @click-right-icon.stop="onSearchCancel"
+      />
+      <div class="head-card">
+        <div class="structure-head">
+          <div class="blue-rectangle" />
+          <div style="margin-top: 5px; margin-left: 5px">组织架构</div>
+        </div>
+        <div style="color: #b7c0c4; padding: 8px 13px; font-size: 13px">
+          [总人数]
+        </div>
+      </div>
+      <hr />
+      <div style="margin-top: 1px">
+        <el-tree
+          :props="defaultProps"
+          default-expand-all
+          style="
+            height: calc(-145px - 10px + 100vh);
+            overflow: scroll;
+            margin-left: 10px;
+          "
+          :load="getList"
+          lazy
+        >
+          <template #default="{ node, data }">
+            <div v-if="!data.isShowSelect" class="custom-tree-node">
+              {{ node.label }}
+            </div>
+            <div
+              v-else
+              class="custom-tree-node"
+              @click="handleCheckChange(data)"
+            >
+              <img :src="adressImage" class="addressImage" />
+              {{ node.label }}
+            </div>
+            <span>
+              <a style="color: #d6d6d7; margin-right: 12px">
+                [ {{ data.personSum }} ]
+              </a>
+            </span>
+          </template>
+        </el-tree>
+        <!--        <el-tree-->
+        <!--          style="max-width: 600px"-->
+        <!--          :props="defaultProps"-->
+        <!--          :load="getList"-->
+        <!--          lazy-->
+        <!--        />-->
+      </div>
+      <div class="bottpm-card">
+        <div class="linkTwo" />
+        <div class="footer">
+          <div class="footer-item1">
+            <img :src="archSel" style="height: 24px" />
+            <div style="margin-top: 4px">组织架构</div>
+          </div>
+          <div class="lineOne" />
+          <div class="footer-item2">
+            <img :src="informNotSel" style="height: 24px" />
+            <div @click="handleToPersonInfo">个人信息</div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import searchImg from "@/assets/images/search.png";
+import closeImg from "@/assets/images/close.png";
+import adressImage from "@/assets/images/threePreventionResponsiblePerson/position.png";
+import archSel from "@/assets/images/threePreventionResponsiblePerson/archSel.png";
+import informNotSel from "@/assets/images/threePreventionResponsiblePerson/informNotSel.png";
+import { ElTree } from "element-plus";
+import router from "@/router";
+import type Node from "element-plus/es/components/tree/src/model/node";
+import { getTree } from "@/api/tree";
+
+const propps = defineProps({
+  isShowStructure: Boolean
+});
+const keywords = ref("");
+const onSearchKeyword = () => {};
+const onSearchCancel = () => {};
+const emits = defineEmits(["update:isShowStructure", "confirm"]);
+let defaultProps = reactive({
+  children: "children",
+  label: "label",
+  personSum: "personSum",
+  isLeaf: "isShowSelect"
+});
+const getList = async (node: Node, resolve: (data: Tree[]) => void) => {
+  const id = node.level === 0 ? "1" : node.id;
+   let res = await getTree(id)
+  resolve(res.data);
+};
+const fetchData = async () => {
+
+}
+const handleCheckChange = data => {
+  emits("confirm", {
+    label: data.label,
+    value: data.parentLabel,
+    id: data.id
+  });
+  emits("update:isShowStructure", false);
+};
+const handleToPersonInfo = () => {
+  router.push({ name: "EditPersonInformation" });
+};
+
+interface Tree {
+  name: string;
+  leaf?: boolean;
+}
+
+let time = 0;
+const loadNode = (
+  node: Node,
+  resolve: (data: Tree[]) => void,
+  reject: () => void
+) => {
+  if (node.level === 0) {
+    return resolve([{ name: "region" }]);
+  }
+  time++;
+  if (node.level >= 1) {
+    setTimeout(() => {
+      if (time > 3) {
+        return resolve([
+          { name: "zone1", leaf: true },
+          { name: "zone2", leaf: true },
+          { name: "zone3", leaf: true }
+        ]);
+      } else {
+        return reject();
+      }
+    }, 3000);
+  }
+};
+</script>
+
+<style scoped lang="scss">
+.block1 {
+  width: 100%;
+  height: 100%;
+  background-color: #ffffff;
+}
+.head-card {
+  display: flex;
+  flex-direction: row;
+  justify-content: space-between;
+  background-color: white;
+}
+.structure-head {
+  display: flex;
+  background-color: #ffffff;
+  padding-left: 20px;
+  padding-bottom: 5px;
+  align-items: center;
+}
+.blue-rectangle {
+  width: 6px;
+  height: 20px;
+  background-image: linear-gradient(180deg, #00fce7 0%, #2c81ff 100%);
+  border-radius: 0 3px 0 0;
+  margin-left: -10px;
+}
+.custom-tree-node {
+  display: flex;
+  width: 100%;
+  margin-right: 12px;
+}
+.addressImage {
+  height: 13px;
+  margin-top: 4px;
+}
+.linkTwo {
+  height: 0.5px;
+  border-top: solid #e1e1e1 1px;
+}
+.footer {
+  position: fixed;
+  z-index: 9999;
+  bottom: 0;
+  left: 0;
+  width: 100%;
+  height: 60px;
+  background: #ffffff;
+  display: flex;
+  justify-content: space-around;
+  align-items: center;
+}
+.footer-item1 {
+  display: flex;
+  flex-direction: row;
+  color: #1890ff;
+  margin-left: 20px;
+}
+.lineOne {
+  width: 1px;
+  height: 60px;
+  background-color: #e1e1e1;
+}
+.footer-item2 {
+  display: flex;
+  flex-direction: row;
+  color: #909090;
+  margin-right: 20px;
+}
+.bottpm-card {
+  display: flex;
+  flex-direction: column;
+}
+</style>

+ 7 - 2
src/views/threePreventionResponsiblePerson/personInformation.vue

@@ -12,7 +12,7 @@
         >
           <div class="information-box">
             <div class="circle2">
-              <img :src="personalInformation.profile_picture" alt="" />
+              <img :src="personalInformation.state === false ? offlineUser : onlineUser" alt="" />
             </div>
             <div style="margin: 30px 15px">
               <div class="online-box">
@@ -60,6 +60,8 @@
 <script setup lang="ts">
 import { ref } from "vue";
 import profile from "@/assets/images/tempImage/用户.png";
+import offlineUser from "@/assets/images/threePreventionResponsiblePerson/offlineUsers.png";
+import onlineUser from "@/assets/images/threePreventionResponsiblePerson/onlineUsers.png";
 
 const isShowInformation = ref(false);
 const personalInformation = ref({
@@ -126,6 +128,7 @@ const showPersonalInformation = item => {
   color: dodgerblue;
   font-weight: bold;
   margin-left: 5px;
+  border-radius: 2px;
   &:nth-child(1) {
     margin-left: 0;
   }
@@ -151,7 +154,9 @@ const showPersonalInformation = item => {
   padding: 0px 10px;
   height: 15px;
   margin-left: 15px;
-  margin-top: 5px;
+  margin-top: 4px;
+  padding-bottom: 18px;
+  border-radius: 2px;
 }
 .notOnline {
   background-color: limegreen;