From 0d32ef0479cb7d7d0f24b4e866994d43dfaf82e6 Mon Sep 17 00:00:00 2001
From: 马宇豪 <978517621@qq.com>
Date: 星期二, 04 六月 2024 13:12:41 +0800
Subject: [PATCH] 添加通讯录

---
 /dev/null                                    |    8 
 src/views/Admin/contactBook/contactors.vue   |  376 ++++++++++++
 src/layout/menu/index.js                     |   69 ++
 src/views/Admin/massSend.vue                 |  194 ++++-
 src/views/Admin/contactBook/structure.vue    |  243 +++++++
 src/views/Admin/components/contactorsMod.vue |  397 ++++++++++++
 src/views/Admin/contactBook/subMenu.vue      |   45 +
 src/api/contactBook.js                       |  120 +++
 src/router/index.js                          |   12 
 src/views/Admin/responsor.vue                |  338 ++++++++++
 10 files changed, 1,728 insertions(+), 74 deletions(-)

diff --git a/src/api/contactBook.js b/src/api/contactBook.js
new file mode 100644
index 0000000..3e92f78
--- /dev/null
+++ b/src/api/contactBook.js
@@ -0,0 +1,120 @@
+//将拦截器整体导入
+import request from '@/util/request'//导入已经写好的拦截器
+
+// 获取架构树
+export function getStructure(){
+    return request({
+        url: '/sys/districtInfo/org',
+        method: 'get'
+    })
+}
+
+// 新增
+export function addDep(data){
+    return request({
+        url: '/org/structure/add',
+        method: 'post',
+        data: data,
+    })
+}
+
+// 修改
+export function editDep(data){
+    return request({
+        url: '/org/structure/update',
+        method: 'post',
+        data: data,
+    })
+}
+
+// 修改
+export function editArea(data){
+    return request({
+        url: '/sys/districtInfo/update',
+        method: 'post',
+        data: data,
+    })
+}
+
+// 删除
+export function delStructure(id){
+    return request({
+        url: '/org/structure/delete/' + id,
+        method: 'delete'
+    })
+}
+
+// 更新统计
+export function getUpdateData(){
+    return request({
+        url: '/org/user/task/statistic',
+        method: 'get'
+    })
+}
+
+// 下发更新任务
+export function deliverUpdate(){
+    return request({
+        url: '/org/user/task/update',
+        method: 'get'
+    })
+}
+
+// 架构详情
+export function getStructureDetail(id){
+    return request({
+        url: '/org/structure/findById/' + id,
+        method: 'get'
+    })
+}
+
+// 分页
+export function getContactors(data){
+    return request({
+        url: '/org/user/page',
+        method: 'post',
+        data: data,
+    })
+}
+
+// 新增
+export function addContactors(data){
+    return request({
+        url: '/org/user/add',
+        method: 'post',
+        data: data,
+    })
+}
+
+// 更新
+export function updateContactors(data){
+    return request({
+        url: '/org/user/update',
+        method: 'post',
+        data: data,
+    })
+}
+
+// 删除
+export function delContactors(id){
+    return request({
+        url: '/org/user/delete/' + id,
+        method: 'delete'
+    })
+}
+
+// 无需更新
+export function noUpdate(id){
+    return request({
+        url: '/org/user/no/update/' + id,
+        method: 'get'
+    })
+}
+
+// 通讯录下拉接口
+export function getNewAddressBook(){
+    return request({
+        url: '/org/structure/select/user',
+        method: 'get'
+    })
+}
\ No newline at end of file
diff --git a/src/layout/menu/index.js b/src/layout/menu/index.js
index 3ee28c2..604b631 100644
--- a/src/layout/menu/index.js
+++ b/src/layout/menu/index.js
@@ -77,18 +77,34 @@
 				},
 				{
 					MenuID: "33",
-					MenuTitle: "平级接收人管理",
+					MenuTitle: "(旧)平级接收人管理",
 					MenuPath: "/samelevel",
 				},
 				{
 					MenuID: "34",
-					MenuTitle: "平级接收人分组",
+					MenuTitle: "(旧)平级接收人分组",
 					MenuPath: "/samelevelGroup",
 				},
 				{
 					MenuID: "35",
 					MenuTitle: "原通讯录",
 					MenuPath: "/addressBook",
+				}
+			],
+		},
+		{
+			MenuTitle: "通讯录管理",
+			Icon: "book",
+			MenuID: "5",
+			Children: [{
+				MenuID: "51",
+				MenuTitle: "责任人管理",
+				MenuPath: "/contactors",
+			},
+				{
+					MenuID: "52",
+					MenuTitle: "组织架构维护",
+					MenuPath: "/structure",
 				}
 			],
 		},
@@ -157,7 +173,34 @@
 					MenuPath: "/msgReview",
 				},
 			],
-		}
+		},
+		{
+			MenuTitle: "短信管理",
+			Icon: "message",
+			MenuID: "3",
+			Children: [{
+				MenuID: "31",
+				MenuTitle: "常规群发",
+				MenuPath: "/massSend",
+			}
+			],
+		},
+		{
+			MenuTitle: "通讯录管理",
+			Icon: "book",
+			MenuID: "5",
+			Children: [{
+				MenuID: "51",
+				MenuTitle: "责任人管理",
+				MenuPath: "/contactors",
+			},
+				{
+					MenuID: "52",
+					MenuTitle: "组织架构维护",
+					MenuPath: "/structure",
+				}
+			],
+		},
 	],
 	workerMenu: [{
 		MenuTitle: "首页",
@@ -232,12 +275,12 @@
 				},
 				{
 					MenuID: "33",
-					MenuTitle: "平级接收人管理",
+					MenuTitle: "(旧)平级接收人管理",
 					MenuPath: "/samelevel",
 				},
 				{
 					MenuID: "34",
-					MenuTitle: "平级接收人分组",
+					MenuTitle: "(旧)平级接收人分组",
 					MenuPath: "/samelevelGroup",
 				},
 				{
@@ -248,6 +291,22 @@
 			],
 		},
 		{
+			MenuTitle: "通讯录管理",
+			Icon: "book",
+			MenuID: "5",
+			Children: [{
+				MenuID: "51",
+				MenuTitle: "责任人管理",
+				MenuPath: "/contactors",
+			},
+				{
+					MenuID: "52",
+					MenuTitle: "组织架构维护",
+					MenuPath: "/structure",
+				}
+			],
+		},
+		{
 			MenuTitle: "设置",
 			Icon: "setting",
 			MenuID: "4",
diff --git a/src/router/index.js b/src/router/index.js
index 8c9b385..d7648ea 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -100,6 +100,18 @@
 			meta: { title: '原通讯录' },
 			component: () => import('@/views/Admin/addressBook'),
 		},
+		{
+			path: '/contactors',
+			name: 'contactors',
+			meta: { title: '责任人管理' },
+			component: () => import('@/views/Admin/contactBook/contactors'),
+		},
+		{
+			path: '/structure',
+			name: 'structure',
+			meta: { title: '组织架构管理' },
+			component: () => import('@/views/Admin/contactBook/structure'),
+		},
       {
         path: '/user',
         name: 'user',
diff --git a/src/views/Admin/Torelease.vue b/src/views/Admin/Torelease.vue
deleted file mode 100644
index 02409e3..0000000
--- a/src/views/Admin/Torelease.vue
+++ /dev/null
@@ -1,8 +0,0 @@
-<template>
-</template>
-
-<script>
-</script>
-
-<style>
-</style>
\ No newline at end of file
diff --git a/src/views/Admin/components/contactorsMod.vue b/src/views/Admin/components/contactorsMod.vue
new file mode 100644
index 0000000..6200c7c
--- /dev/null
+++ b/src/views/Admin/components/contactorsMod.vue
@@ -0,0 +1,397 @@
+<template>
+  <a-modal
+      :title="title"
+      :visible="visible"
+      centered
+      :confirm-loading="confirmLoading"
+      width="50%"
+      cancelText="取消"
+      okText="确认"
+      @ok="onSubmit"
+      @cancel="handleCancel"
+      :afterClose="clearMod"
+  >
+    <a-form-model ref="ruleForm" :rules="rules" :model="form" :label-col="labelCol" :wrapper-col="wrapperCol" :colon="false">
+      <a-row>
+        <a-col :span="12">
+          <a-form-model-item label="姓名" prop="name">
+            <a-input v-model.trim="form.name" :disabled="isView"/>
+          </a-form-model-item>
+        </a-col>
+        <a-col :span="12">
+          <a-form-model-item label="手机号码" prop="phone">
+            <a-input v-model.trim="form.phone" :disabled="isView"/>
+          </a-form-model-item>
+        </a-col>
+      </a-row>
+      <a-row>
+        <a-col :span="12">
+          <a-form-model-item label="所属单位" prop="company">
+            <a-input v-model.trim="form.company" :disabled="isView"/>
+          </a-form-model-item>
+        </a-col>
+        <a-col :span="12">
+          <a-form-model-item label="职务" prop="post">
+            <a-input v-model.trim="form.post" :disabled="isView"/>
+          </a-form-model-item>
+        </a-col>
+      </a-row>
+      <a-row>
+        <a-col :span="12">
+          <a-form-model-item label="行政区划">
+            <a-tree-select
+                v-model="areaId"
+                style="width: 100%"
+                :dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
+                :tree-data="areaData"
+                placeholder="行政区划"
+                :replaceFields="replaceFields"
+                disabled
+            />
+          </a-form-model-item>
+        </a-col>
+        <a-col :span="12">
+          <a-form-model-item label="组织架构">
+            <a-input v-model="orgName" disabled/>
+          </a-form-model-item>
+        </a-col>
+      </a-row>
+      <a-row>
+        <a-col :span="12">
+          <a-form-model-item label="排位顺序">
+            <a-input type="number" v-model.number="form.orderNum" :disabled="isView"/>
+          </a-form-model-item>
+        </a-col>
+      </a-row>
+      <a-row>
+        <a-col :span="24">
+<!--          <template v-for="(item,index) in options">-->
+            <a-form-model-item label="责任类别"  :label-col="{span: 3}" :wrapper-col="{span: 14}" prop="typeList">
+              <a-checkbox-group
+                  v-model="form.typeList"
+                  :options="options"
+                  @change="onTypeChange"
+                  :disabled="isView"
+                  style="width: 100%;"
+              />
+            </a-form-model-item>
+<!--          </template>-->
+        </a-col>
+      </a-row>
+      <a-row>
+        <a-col :span="24" v-for="(item,index) in options">
+          <a-form-model-item v-if="item.children && item.children.length>0 && form.typeList.find(i=>i == item.label)" :label="item.label" :label-col="{span: 3}" :wrapper-col="{span: 14}" :prop="'tagList.' + item.label">
+            <a-checkbox-group
+                v-model="form.tagList[item.label]"
+                :options="item.children"
+                @change="onTagChange"
+                :disabled="isView"
+            />
+          </a-form-model-item>
+        </a-col>
+      </a-row>
+    </a-form-model>
+  </a-modal>
+</template>
+
+<script>
+import {addContactors,updateContactors} from '@/api/contactBook'
+import {verifySimplePhone} from "@/util/validate";
+import {getDistrictInfo} from "@/api/login";
+export default {
+  name: 'addressUserMod',
+  props: ['groupList'],
+  data () {
+    let validatePhone = (rule, value, callback)=>{
+      if(value === ''){
+        callback(new Error('请输入手机号'))
+      }else{
+        if(!verifySimplePhone(value)){
+          callback(new Error('手机号格式有误'))
+        }else{
+          callback()
+        }
+      }
+    }
+
+    return {
+      title: '新增责任人',
+      visible: false,
+      isView: false,
+      confirmLoading: false,
+      areaData: [],
+      labelCol: { span: 6 },
+      wrapperCol: { span: 14 },
+      areaId: null,
+      orgName: '',
+      form: {
+        id: null,
+        name: '',
+        phone: '',
+        company: '',
+        post: '',
+        orgStructureId: null,
+        districtId: null,
+        districtCode: '',
+        orderNum: 0,
+        typeList: [],
+        tagList: {}
+      },
+      tagList: [],
+      rules: {
+        name: [{ required: true, message: '请输入姓名', trigger: 'blur'}],
+        phone: [{ required: true, validator: validatePhone, trigger: 'blur'}],
+        company: [{ required: true, message: '请输入单位名称', trigger: 'blur'}],
+        post: [{ required: true, message: '请输入职务', trigger: 'change'}],
+        typeList: [{ required: true, message: '请选择责任类别', trigger: 'change'}],
+        tagList: []
+      },
+      options: [
+        {
+          value: '党委政府',
+          label: '党委政府',
+          children: [
+            {
+              value: '主要领导',
+              label: '主要领导',
+            },
+            {
+              value: '分管领导',
+              label: '分管领导',
+            }
+          ]
+        },
+        {
+          value: '两委三部',
+          label: '两委三部',
+          children: [
+            {
+              value: '安委会成员单位',
+              label: '安委会成员单位'
+            },
+            {
+              value: '减灾委成员单位',
+              label: '减灾委成员单位'
+            },
+            {
+              value: '防汛抗旱指挥部',
+              label: '防汛抗旱指挥部'
+            },
+            {
+              value: '抗震救灾指挥部',
+              label: '抗震救灾指挥部'
+            },
+            {
+              value: '森林草原防灭火指挥部',
+              label: '森林草原防灭火指挥部'
+            }
+          ]
+        },
+        {
+          value: '应急部门',
+          label: '应急部门',
+          children: [
+            {
+              value: '应急部门',
+              label: '应急部门'
+            }
+          ]
+        },
+        {
+          value: '救援队伍',
+          label: '救援队伍',
+          children: [
+            {
+              value: '救援队伍',
+              label: '救援队伍'
+            }
+          ]
+        }
+      ],
+      replaceFields: {
+        children:'children',
+        title:'name',
+        key:'id',
+        value: 'id'
+      },
+    }
+  },
+  created() {
+    const t = this
+    t.getDistrictInfo()
+  },
+
+  methods:{
+    openDialog(type,data,areaId,orgName,orgId){
+      const t = this
+      t.createRules()
+      t.areaId = Number(areaId)
+      t.orgName = orgName
+      if(type == 'add'){
+        t.title = '新增责任人'
+        t.isView = false
+        t.form = {
+          id: null,
+          name: '',
+          phone: '',
+          company: '',
+          post: '',
+          orgStructureId: Number(orgId),
+          districtId: t.areaId,
+          districtCode: t.findCodeById(t.areaData,t.areaId),
+          orderNum: 0,
+          typeList: [],
+          tagList: {}
+        }
+      }else{
+        for(let i in data){
+          if(t.isValidKey(i,t.form)){
+            t.form[i] = data[i]
+          }
+        }
+        t.form.typeList = []
+        t.form.tagList = {}
+        t.form.typeList = data.orgUserTypes.map(i=>i.typeName)
+        // for(let i of data.orgUserTypes){
+        //   t.form.tagList[i.typeName] = i.orgUserTags.map(j=>j.tagName)
+        // }
+        // Vue.set方法添加新属性确保响应式
+        for (let i of data.orgUserTypes) {
+          t.$set(t.form.tagList, i.typeName, i.orgUserTags.map(j => j.tagName));
+        }
+        if(type == 'edit'){
+          t.title = '编辑责任人'
+          t.isView = false
+        }else{
+          t.title = '责任人详情'
+          t.isView = true
+        }
+      }
+      t.visible = true
+    },
+    isValidKey(key, object){
+      return key in object;
+    },
+    createRules(){
+      for(let i of this.options){
+        this.rules.tagList[i.label] = (
+            {
+              required: true,
+              validator: (rule, value, callback) => {
+                if (!value || value.length === 0) {
+                  callback(new Error('请选择标签类别'));
+                } else {
+                  callback();
+                }
+              },
+              trigger: 'change'
+            }
+        )
+      }
+    },
+    onTypeChange(checkedValue) {
+      console.log(checkedValue,this.form.typeList,666);
+    },
+
+    onTagChange(checkedValue) {
+      console.log(checkedValue,this.form.tagList,777);
+    },
+
+    clearMod(){
+      this.$refs.ruleForm.clearValidate()
+      this.$refs.ruleForm.resetFields()
+      this.rules.tagList = []
+    },
+
+    onSubmit() {
+      this.$refs.ruleForm.validate(valid => {
+        if (valid) {
+          if(this.title == '新增责任人'){
+            const {id,tagList,...data} = this.form
+            data.typeList = this.form.typeList.map(item=>{
+              const newTagList = this.form.tagList[item].map(i=>{
+                return {
+                  tagName: i
+                }
+              })
+              return {
+                typeName: item,
+                tagList: newTagList
+              }
+            })
+            addContactors(data).then((res)=>{
+              if(res.data.code == 100){
+                this.$message.success('新增责任人成功')
+                this.$emit('refresh')
+                this.visible = false
+              }else{
+                this.$message.error(res.data.msg)
+              }
+            })
+          }else if(this.title == '编辑责任人'){
+            const {tagList,...data} = this.form
+            data.typeList = this.form.typeList.map(item=>{
+              const newTagList = this.form.tagList[item].map(i=>{
+                return {
+                  tagName: i
+                }
+              })
+              return {
+                typeName: item,
+                tagList: newTagList
+              }
+            })
+            updateContactors(data).then((res)=>{
+              if(res.data.code == 100){
+                this.$message.success('修改责任人成功')
+                this.$emit('refresh')
+                this.visible = false
+              }else{
+                this.$message.error(res.data.msg)
+              }
+            })
+          }else{
+            this.visible = false
+          }
+        } else {
+          console.log('error submit!!');
+          return false;
+        }
+      });
+    },
+
+    async getDistrictInfo(){
+      let res = await getDistrictInfo()
+      if(res.data.code == 100){
+        this.areaData = res.data.data
+      } else {
+        this.$message.warning(res.data.msg);
+      }
+    },
+
+    findCodeById(data, id) {
+      for (let item of data) {
+        if (item.id === id) {
+          return item.code;
+        }
+        if (item.children && item.children.length > 0) {
+          const code = this.findCodeById(item.children, id);
+          if (code) {
+            return code;
+          }
+        }
+      }
+      return null; // 如果未找到,返回 null
+    },
+
+    handleCancel(e) {
+      const t = this
+      t.visible = false;
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+
+</style>
diff --git a/src/views/Admin/contactBook/contactors.vue b/src/views/Admin/contactBook/contactors.vue
new file mode 100644
index 0000000..9dc8b3c
--- /dev/null
+++ b/src/views/Admin/contactBook/contactors.vue
@@ -0,0 +1,376 @@
+<template>
+  <div class="inner">
+    <a-row>
+      <a-col :span="4">
+        <a-menu
+            style="width: calc(100% - 20px)"
+            :default-selected-keys="currentKey"
+            :open-keys.sync="openKeys"
+            :selectedKeys="currentKey"
+            mode="inline"
+            @click="handleClick"
+        >
+          <template v-for="(item,index) in treeData">
+            <sub-menu ref="subMenuRef" :key="item.id+'-'+item.name" :menu-info="item"></sub-menu>
+          </template>
+        </a-menu>
+      </a-col>
+      <a-col :span="20">
+        <div style="display: flex;justify-content: space-between">
+          <div>最新更新要求下发时间:{{updateData.gmtModified?updateData.gmtModified:'暂无数据'}}</div>
+          <div style="display: flex;align-items: center">
+            <div>总数:<span style="color: blue;margin-right: 10px">{{updateData.totalCount?updateData.totalCount:'暂无数据'}}</span>待更新:<span style="color: orange;margin-right: 10px">{{updateData.updateNoCount?updateData.updateNoCount:'暂无数据'}}</span>已更新:<span style="color: green;margin-right: 10px">{{updateData.updateYesCount?updateData.updateYesCount: '暂无数据'}}</span>更新率:<span style="color: blue;margin-right: 10px">{{updateData.updatedRate?updateData.updatedRate + '%':'暂无数据'}}</span></div>
+            <a-button type="danger" @click="deliverTask" v-if="!unittype || unittype == 1">下发更新任务</a-button>
+          </div>
+        </div>
+        <div style="margin: 20px 0">
+          <a-button  type="primary" style="margin-right: 10px" @click="editData('add',{})">新增</a-button>
+          <a-button  type="primary" @click="massImport()">批量导入</a-button>
+        </div>
+        <div class="table-cont">
+          <a-table :columns="columns" :data-source="tableData" :pagination="pagination" :rowKey="record=>record.id" bordered>
+            <template #index="text,record,index">
+              {{ index + 1 }}
+            </template>
+            <template #orgName="text,record,index">
+              {{currentKey.length>0?currentKey[0].split('-')[1]: ''}}
+            </template>
+            <template #orgUserTypes="text,record,index">
+              {{record.orgUserTypes?record.orgUserTypes.map(i=>i.typeName + '(' + i.orgUserTags.map(j=>j.tagName).join('/') +')').join(','): ''}}
+            </template>
+            <template #updateStatus="text,record,index">
+              <span v-if="text == 0" style="color: green">已更新</span>
+              <span v-else style="color: red">待更新</span>
+            </template>
+            <template #action="action,row">
+              <a-button type="link" @click="editData('view',row)">详情</a-button>
+              <a-button type="link" @click="editData('edit',row)">更新</a-button>
+              <a-button type="link" v-if="row.updateStatus == 1" @click="noNeed(row)">无需更改</a-button>
+              <a-button type="link" class="delBtn" @click="delData(row)">删除</a-button>
+            </template>
+          </a-table>
+        </div>
+      </a-col>
+      <contactors-mod ref="contactMod" @refresh="getUserList()"></contactors-mod>
+    </a-row>
+  </div>
+</template>
+
+<script>
+import {getUserInfo} from "@/util/storage";
+import {
+  getStructure,
+  getStructureDetail,
+  getUpdateData,
+  getContactors,
+  delContactors,
+  noUpdate, deliverUpdate
+} from "@/api/contactBook";
+import subMenu from "@/views/Admin/contactBook/subMenu";
+import contactorsMod from "@/views/Admin/components/contactorsMod"
+
+export default {
+  name: 'sameLevel',
+  components: {
+    subMenu,
+    contactorsMod
+  },
+  data () {
+    return {
+      openKeys: [],
+      areaVal: [],
+      unittype: null,
+      districtId: null,
+      currentKey: [],
+      search:{
+        pageIndex: 1,
+        pageSize: 10,
+        searchParams: {
+          name: '',
+          phone: '',
+          orgStructureId: null
+        }
+      },
+      columns:[
+        {
+          title: '序号',
+          dataIndex: 'index',
+          scopedSlots: {
+            customRender: 'index'
+          }
+        },
+        {
+          title: '姓名',
+          dataIndex: 'name',
+          key: 'name',
+          align: 'center'
+        },
+        {
+          title: '所属组织架构',
+          dataIndex: 'orgName',
+          scopedSlots: {
+            customRender: 'orgName'
+          }
+        },
+        {
+          title: '所属单位',
+          dataIndex: 'company',
+          key: 'company',
+        },
+        {
+          title: '职务',
+          dataIndex: 'post',
+          key: 'post',
+        },
+        {
+          title: '电话号码',
+          dataIndex: 'phone',
+          key: 'phone',
+        },
+        {
+          title: '责任类型',
+          dataIndex: 'orgUserTypes',
+          scopedSlots: {
+            customRender: 'orgUserTypes'
+          }
+        },
+        {
+          title: '更新状态',
+          dataIndex: 'updateStatus',
+          scopedSlots: {
+            customRender: 'updateStatus'
+          }
+        },
+        {
+          title: '操作',
+          width: '12%',
+          key: 'action',
+          scopedSlots: { customRender: 'action' }
+        },
+      ],
+      treeData: [],
+      updateData: {},
+      tableData: [],
+      pagination: {
+        current: 1,
+        defaultCurrent: 1,
+        defaultPageSize: 10,
+        total: 0,
+        onChange: ( page, pageSize ) => this.onPageChange(page,pageSize),
+        showTotal: total => `共 ${total} 条`
+      },
+      fieldNames:{
+        label: 'name',
+        value: 'id',
+        children: 'children'
+      },
+      currentId: null
+    }
+  },
+  created() {
+    const t = this
+    t.unittype = getUserInfo().unittype
+    t.districtId = getUserInfo().districtId
+    t.getUserList()
+    t.getUpdataData()
+    t.getStructure()
+  },
+  mounted() {
+
+  },
+  watch: {
+    openKeys(val) {
+      console.log('openKeys', val);
+    }
+  },
+  methods:{
+    async getStructure(){
+      const t = this
+      const res = await getStructure()
+      if(res.data.code == 100){
+        t.treeData = res.data.data
+        const firstItem = this.firstIdWithOrgStructures(res.data.data[0])
+        if(firstItem){
+          t.openKeys =  [firstItem.id +'-'+  firstItem.name]
+          t.currentId = firstItem.id
+          t.currentKey = [firstItem.orgStructures[0].id +'-'+  firstItem.orgStructures[0].orgName]
+        }else{
+          t.$message.warning('暂无可操作的单位,请先进入“组织架构维护页面”新建相应的本级单位')
+        }
+      }else{
+        t.$message.warning(res.data.msg)
+      }
+    },
+
+
+    firstIdWithOrgStructures(node) {
+      if (node.orgStructures && node.orgStructures.length > 0) {
+        return node
+      }
+
+      if (node.children && node.children.length > 0) {
+        for (let child of node.children) {
+          const result = this.firstIdWithOrgStructures(child);
+          if (result) {
+            return result
+          }
+        }
+      }
+      return null;
+    },
+
+    async getUpdataData(){
+      const t = this
+      const res = await getUpdateData();
+      if(res.data.code == 100){
+        t.updateData = res.data.data
+      }else{
+        t.$message.warning(res.data.msg);
+      }
+    },
+
+
+    handleClick(e) {
+      console.log(e)
+      this.currentId = e.keyPath[1]?e.keyPath[1].split('-')[0]:e.keyPath[0].split('-')[0]
+      this.search = {
+        pageIndex: 1,
+        pageSize: 10,
+        searchParams: {
+          name: '',
+          phone: '',
+          orgStructureId: null
+        }
+      }
+      this.currentKey = [e.key]
+      this.search.searchParams.orgStructureId = Number(e.key.split('-')[0])
+      this.getUserList()
+    },
+    titleClick(e) {
+      console.log('titleClick', e);
+    },
+    async getUserList(){
+      const t = this
+      const res = await getContactors(t.search);
+      if(res.data.code == 100){
+        t.tableData = res.data.data
+        t.pagination.total = res.data.total
+      }else{
+        t.$message.warning(res.data.msg);
+      }
+    },
+
+    massImport(){
+      this.$message.warning('批量导入请联系管理人员')
+    },
+
+    resetSearch(){
+      const t = this
+      t.areaVal = []
+      t.search = {
+        pageIndex: 1,
+        pageSize: 10,
+      }
+      t.getUserList()
+    },
+
+    editData(type,data){
+      const t = this
+      if(type == 'add' && (!t.currentId || !t.currentKey)){
+        t.$message.warning('暂无可操作的单位,请先进入“组织架构维护页面”新建相应的本级单位')
+        return
+      }
+      const areaId = t.currentId
+      const orgName = t.currentKey.length>0?t.currentKey[0].split('-')[1]: ''
+      const orgId = t.currentKey.length>0?t.currentKey[0].split('-')[0]: null
+      t.$refs.contactMod.openDialog(type,data,areaId,orgName,orgId)
+    },
+
+    async delData(row){
+      const t = this
+      this.$confirm({
+        title: '提示',
+        content: h => <div>是否删除该条信息?</div>,
+        cancelText: '取消',
+        okText: '确认',
+        centered: true,
+        onOk() {
+          delContactors(row.id).then(res=>{
+            if(res.data.code == 100){
+              t.$message.success('删除成功');
+              t.getUserList()
+            }else{
+              t.$message.warning(res.data.msg);
+            }
+          })
+        },
+        onCancel() {
+          console.log('Cancel');
+        },
+      });
+    },
+
+    async deliverTask(){
+      const t = this
+      this.$confirm({
+        title: '提示',
+        content: h => <div>是否确认下发更新任务?</div>,
+        cancelText: '取消',
+        okText: '确认',
+        centered: true,
+        onOk() {
+          deliverUpdate().then(res=>{
+            if(res.data.code == 100){
+              t.$message.success('下发成功')
+              t.getUpdataData()
+              t.getUserList()
+            }else{
+              t.$message.warning(res.data.msg);
+            }
+          })
+        },
+        onCancel() {
+          console.log('Cancel');
+        },
+      });
+    },
+
+    async noNeed(row){
+      const t = this
+      this.$confirm({
+        title: '提示',
+        content: h => <div>是否确认该信息无需更改?</div>,
+        cancelText: '取消',
+        okText: '确认',
+        centered: true,
+        onOk() {
+          noUpdate(row.id).then(res=>{
+            if(res.data.code == 100){
+              t.$message.success('提交成功');
+              t.getUserList()
+            }else{
+              t.$message.warning(res.data.msg);
+            }
+          })
+        },
+        onCancel() {
+          console.log('Cancel');
+        },
+      });
+    },
+
+    onPageChange(page, pageSize) {
+      const t= this
+      t.pagination.current = page
+      t.search.pageIndex = page
+      t.getUserList()
+    },
+  }
+}
+</script>
+
+<style lang="less" scoped>
+.delBtn{
+  color: @danger
+}
+</style>
diff --git a/src/views/Admin/contactBook/structure.vue b/src/views/Admin/contactBook/structure.vue
new file mode 100644
index 0000000..85b6e41
--- /dev/null
+++ b/src/views/Admin/contactBook/structure.vue
@@ -0,0 +1,243 @@
+<template>
+  <div class="inner">
+    <a-table
+          :columns="columns"
+          :data-source="tableData"
+          :expanded-row-keys.sync="expandedRowKeys"
+          :rowKey="record=>record.id"
+          :pagination="false"
+      >
+      <template #name="name">
+        <span style="color:#40a9ff;font-weight: bolder">{{name}}</span>
+      </template>
+        <template #action="action,row">
+          <a-button type="link" @click="editData(row)">编辑</a-button>
+          <a-button type="primary" @click="openAdd('add',row)">增加本级单位</a-button>
+        </template>
+      <template #expandedRowRender="text">
+        <a-table
+            :columns="innerColumns"
+            :data-source="text.orgStructures"
+            :rowKey="record=>record.id"
+            :pagination="false"
+            v-if="text.orgStructures && text.orgStructures.length>0"
+            :showHeader="false"
+        >
+          <template #action="action,row">
+            <a-button type="link" @click="openAdd('edit',row)">编辑</a-button>
+            <a-button type="link" class="delBtn" @click="delData(row)">删除</a-button>
+          </template>
+        </a-table>
+      </template>
+    </a-table>
+    <a-modal v-model="showDialog" :title="editTitle" :ok-text="editTitle" cancel-text="取消" @ok="addData" centered :afterClose="clearMod">
+      <a-form-model ref="ruleForm" :rules="rules" :model="form" :label-col="labelCol" :wrapper-col="wrapperCol" :colon="false">
+        <a-form-model-item label="单位名称" prop="orgName">
+          <a-input v-model="form.orgName"/>
+        </a-form-model-item>
+      </a-form-model>
+    </a-modal>
+    <a-modal v-model="showAreaDialog" title="修改" ok-text="确认" cancel-text="取消" @ok="confirmUpdate" centered>
+      <a-form-model ref="areaRuleForm" :rules="areaRules" :model="areaForm" :label-col="labelCol" :wrapper-col="wrapperCol" :colon="false">
+        <a-form-model-item label="区划名称" prop="name">
+          <a-input v-model="areaForm.name"/>
+        </a-form-model-item>
+      </a-form-model>
+    </a-modal>
+  </div>
+</template>
+
+<script>
+import {getUserInfo} from "@/util/storage";
+import {getStructure, addDep, editDep, delStructure, editArea} from "@/api/contactBook";
+export default {
+  name: 'structure',
+  components: {
+
+  },
+  data () {
+    return {
+      areaVal: [],
+      unittype: null,
+      districtId: null,
+      columns:[
+        {
+          title: '名称',
+          dataIndex: 'name',
+          key: 'name',
+          scopedSlots: {
+            customRender: 'name'
+          },
+        },
+        {
+          title: '操作',
+          width: '12%',
+          key: 'action',
+          scopedSlots: { customRender: 'action' }
+        },
+      ],
+      innerColumns: [
+        {
+          title: '名称',
+          dataIndex: 'orgName',
+          key: 'orgName',
+        },
+        {
+          title: '操作',
+          width: '12%',
+          key: 'action',
+          scopedSlots: { customRender: 'action' }
+        },
+      ],
+      form: {
+        orgName: '',
+        districtId: null,
+        districtCode: ''
+      },
+      areaForm: {
+        id: null,
+        name: ''
+      },
+      labelCol: { span: 4 },
+      wrapperCol: { span: 14 },
+      rules: {
+        orgName: [{ required: true, message: '请输入单位名称', trigger: 'blur'}],
+      },
+      areaRules: {
+        name: [{ required: true, message: '请输入区划名称', trigger: 'blur'}],
+      },
+      innerData: [],
+      tableData: [],
+      editTitle: '新增',
+      expandedRowKeys: [],
+      showDialog: false,
+      showAreaDialog: false
+    }
+  },
+  created() {
+    const t = this
+    t.unittype = getUserInfo().unittype
+    t.districtId = getUserInfo().districtId
+    t.getStructure()
+  },
+  methods:{
+    async getStructure(){
+      const t = this
+      const res = await getStructure();
+      if(res.data.code == 100){
+        t.tableData = res.data.data
+      }else{
+        t.$message.warning(res.data.msg);
+      }
+    },
+
+    openAdd(type,row){
+      if(type == 'add'){
+        this.editTitle = '新增'
+        this.form.districtCode = row.code
+      }else{
+        this.editTitle = '修改'
+        this.form.orgName = row.orgName
+      }
+      this.form.districtId = row.id
+      this.showDialog = true
+    },
+
+    addData(){
+      this.$refs.ruleForm.validate(async valid => {
+        if (valid) {
+          if(this.editTitle == '新增'){
+            const res = await addDep(this.form);
+            if(res.data.code == 100){
+              this.$message.success('新增成功');
+              this.showDialog = false
+              await this.getStructure()
+            }else{
+              this.$message.warning(res.data.msg);
+            }
+          }else{
+            const data = {
+              id: this.form.districtId,
+              orgName: this.form.orgName
+            }
+            const res = await editDep(data);
+            if(res.data.code == 100){
+              this.$message.success('修改成功');
+              this.showDialog = false
+              await this.getStructure()
+            }else{
+              this.$message.warning(res.data.msg);
+            }
+          }
+        } else {
+          console.log('error submit!!');
+          return false;
+        }
+      });
+    },
+
+    clearMod(){
+      this.form = {
+        orgName: '',
+        districtId: null,
+        districtCode: ''
+      }
+    },
+
+    editData(row){
+      const t = this
+      t.areaForm.id = row.id
+      t.areaForm.name = row.name
+      t.showAreaDialog = true
+    },
+
+    confirmUpdate(){
+      this.$refs.areaRuleForm.validate(async valid => {
+        if (valid) {
+          const res = await editArea(this.areaForm);
+          if(res.data.code == 100){
+            this.$message.success('修改成功');
+            this.showAreaDialog = false
+            await this.getStructure()
+          }else{
+            this.$message.warning(res.data.msg);
+          }
+        } else {
+          console.log('error submit!!');
+          return false;
+        }
+      })
+    },
+
+    async delData(row){
+      const t = this
+      this.$confirm({
+        title: '提示',
+        content: h => <div>是否删除该条信息?</div>,
+        cancelText: '取消',
+        okText: '确认',
+        centered: true,
+        onOk() {
+          delStructure(row.id).then(res=>{
+            if(res.data.code == 100){
+              t.$message.success('删除成功');
+              t.getStructure()
+            }else{
+              t.$message.warning(res.data.msg);
+            }
+          })
+        },
+        onCancel() {
+          console.log('Cancel');
+        },
+      });
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+.delBtn{
+  color: @danger
+}
+</style>
diff --git a/src/views/Admin/contactBook/subMenu.vue b/src/views/Admin/contactBook/subMenu.vue
new file mode 100644
index 0000000..39cd65e
--- /dev/null
+++ b/src/views/Admin/contactBook/subMenu.vue
@@ -0,0 +1,45 @@
+<template functional>
+  <a-sub-menu :key="props.menuInfo.id+'-'+props.menuInfo.name">
+    <span slot="title"><span>{{props.menuInfo.name + '(' + props.menuInfo.userTotalCount + ')'}}</span></span>
+    <template v-if="props.menuInfo.orgStructures && props.menuInfo.orgStructures.length > 0">
+      <a-menu-item-group :key="props.menuInfo.name + '1'">
+        <a-menu-item :key="dep.id +'-'+dep.orgName" v-for="(dep, i) in props.menuInfo.orgStructures">
+          {{ dep.orgName + '(' + dep.userCount + ')' }}
+        </a-menu-item>
+      </a-menu-item-group>
+    </template>
+    <template v-if="props.menuInfo.children && props.menuInfo.children.length > 0">
+      <a-menu-item-group :key="props.menuInfo.name + '2'">
+        <sub-menu v-for="(child, index) in props.menuInfo.children" :menu-info="child"></sub-menu>
+      </a-menu-item-group>
+    </template>
+  </a-sub-menu>
+</template>
+
+<script>
+import subMenu from "@/views/Admin/contactBook/subMenu";
+export default {
+  name: 'pspSubMenu',
+  components: {
+    subMenu
+  },
+  props: ['menuInfo'],
+  data(){
+    return {
+
+    }
+  },
+  created(){
+
+  },
+  mounted() {
+    console.log(this.$props,55)
+  },
+  methods: {
+
+  }
+}
+</script>
+<style lang="scss" scoped>
+
+</style>
diff --git a/src/views/Admin/massSend.vue b/src/views/Admin/massSend.vue
index 8b6d7db..c1a8a8f 100644
--- a/src/views/Admin/massSend.vue
+++ b/src/views/Admin/massSend.vue
@@ -70,13 +70,52 @@
 <!--        </a-col>-->
 <!--      </a-row>-->
 <!--			<span><b>发布单位:</b>{{form.publishingUnit}}</span>-->
-			<br/><br/>
-			<!-- 子单位-->
+
       <a-row :gutter="24">
         <a-col :span="12">
+          <a-radio-group v-model="isNewTxl" button-style="solid" style="margin-bottom: 20px" @change="changeTxl">
+            <a-radio-button :value="1">
+              新通讯录
+            </a-radio-button>
+            <a-radio-button :value="2">
+              原通讯录
+            </a-radio-button>
+          </a-radio-group>
+        </a-col>
+      </a-row>
+
+      <a-row :gutter="24">
+        <a-col :span="12" v-if="isNewTxl == 1">
+          <div style="display:flex;justify-content: space-between;align-items: center;">
+            <b>新通讯录接收人:</b>
+            <a-checkbox :checked="checkTxlAll1" @change="checkTxlChange1">
+              全选
+            </a-checkbox>
+          </div>
+          <a-form-model-item prop="txlUsers">
+            <a-tree-select
+                show-search
+                tree-checkable
+                style="width: 100%"
+                v-model="form.txlUsers"
+                :dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
+                placeholder="选择新通讯录接收人"
+                allow-clear
+                multiple
+                :maxTagCount="3"
+                @change="onTxlChanges1"
+                @search="onTxlSearch"
+                @select="onTxlSelect"
+                :tree-data="addressBook"
+                :replaceFields="replaceTxlFields"
+            >
+            </a-tree-select>
+          </a-form-model-item>
+        </a-col>
+        <a-col :span="12" v-else>
           <div style="display:flex;justify-content: space-between;align-items: center;">
             <b>原通讯录接收人:</b>
-            <a-checkbox :checked="checkTxlAll" @change="checkTxlChange">
+            <a-checkbox :checked="checkTxlAll2" @change="checkTxlChange2">
               全选
             </a-checkbox>
           </div>
@@ -91,11 +130,11 @@
                 allow-clear
                 multiple
                 :maxTagCount="3"
-                @change="onTxlChanges"
+                @change="onTxlChanges2"
                 @search="onTxlSearch"
                 @select="onTxlSelect"
-                :tree-data="addressBook"
-                :replaceFields="replaceTxlFields"
+                :tree-data="oldAddressBook"
+                :replaceFields="replaceOldTxlFields"
             >
             </a-tree-select>
           </a-form-model-item>
@@ -187,6 +226,7 @@
 import { TreeSelect } from 'ant-design-vue';
 import { massSend } from "@/api/send";
 import {getUserInfo} from "@/util/storage";
+import {getNewAddressBook} from "@/api/contactBook";
 	export default {
 		name: "massSend",
 		data() {
@@ -195,6 +235,7 @@
 				department: '自治区自然灾害综合监测预警中心',
         filteredOptions:[],
         wrapperCol: { span: 24 },
+        isNewTxl: 1,
         form: {
           id: null,
           emergType: null,
@@ -209,23 +250,25 @@
           verticalRecipient: [],
           horizontalRecipient: []
         },
-        checkTxlAll: false,
+        checkTxlAll1: false,
+        checkTxlAll2: false,
         checkAll: false,
         checkSlAll: false,
+        oldAddressBook: [],
         addressBook: [],
         replaceTxlFields: {
+          children:'orgUsers',
+          title:'name',
+          key:'id',
+          value: 'id'
+        },
+        replaceOldTxlFields: {
           children:'userInfos',
           title:'name',
           key:'id',
           value: 'id'
         },
         areaUsers: [],
-        replaceFields: {
-          children:'children',
-          title:'name',
-          key:'id',
-          value: 'id'
-        },
         riskOptions: [
           {name: '地震',value: 1},
           {name: '气象',value: 3},
@@ -244,6 +287,7 @@
           disasterType: [{ required: true, message: '请选择灾种', trigger: 'change'}],
           warningLevel: [{ required: true, message: '请选择预警级别', trigger: 'change'}],
           content: [{ required: true, message: '请输入信息内容', trigger: 'blur'}],
+          txlUsers: [{ required: true, message: '请选择通讯录接收人', trigger: 'blur'}],
           // receiver: [{ required: true, message: '请选择接收单位', trigger: 'change'}],
           // recipient: [{ required: true, message: '请选择平级接收人', trigger: 'change'}]
           // verticalRecipient: [{ required: true, message: '请选择接收单位', trigger: 'change'}],
@@ -256,6 +300,7 @@
       const t = this
       t.form.publishingUnit = t.userInfo.company
       t.getUserByGroup()
+      t.getNewAddressBook()
       t.getSameLevel()
       t.getAreaUsers()
     },
@@ -277,6 +322,31 @@
                   return item
               })
             }
+            t.oldAddressBook = bookData
+          }else{
+            console.log('暂无数据')
+          }
+        }else{
+          this.$message.warning(res.data.msg);
+        }
+      },
+
+      // 获取新通讯录
+      async getNewAddressBook(){
+        let t = this
+        let res = await getNewAddressBook()
+        if(res.data.code == 100){
+          if(res.data.data){
+            let bookData = []
+            bookData = res.data.data.filter(i=>i.orgUsers?.length>0)
+            for(let j of bookData){
+              j['name'] = j.orgName
+              j.id = j.id.toString() + '-' + '1'
+              j.orgUsers.map((item)=>{
+                item.name = item.name + '('+ item.company + ' ' + item.phone.replace(/(\d{3})\d{4}(\d+)/, "$1****$2") + ')'
+                return item
+              })
+            }
             t.addressBook = bookData
           }else{
             console.log('暂无数据')
@@ -284,6 +354,12 @@
         }else{
           this.$message.warning(res.data.msg);
         }
+      },
+
+      changeTxl(e){
+        this.checkTxlAll1 = false
+        this.checkTxlAll2 = false
+        this.form.txlUsers = []
       },
 
       // 获取同级接收人
@@ -320,62 +396,44 @@
       },
 
       //选择子部门部分
-      onTxlChanges(value,label,extra) {
+      onTxlChanges1(value,label,extra) {
         const t = this
         if(t.form.txlUsers.length == 0){
-          t.checkTxlAll = false
+          t.checkTxlAll1 = false
         }
       },
-      checkTxlChange(e) {
+      onTxlChanges2(value,label,extra) {
         const t = this
-        this.checkTxlAll = !this.checkTxlAll
-        if(t.checkTxlAll == true){
+        if(t.form.txlUsers.length == 0){
+          t.checkTxlAll2 = false
+        }
+      },
+      checkTxlChange1(e) {
+        const t = this
+        this.checkTxlAll1 = !this.checkTxlAll1
+        if(t.checkTxlAll1 == true){
           let res = []
           for(let i of t.addressBook){
-            if(i.userInfos && i.userInfos.length>0)
-            res = res.concat(...i.userInfos)
+            if(i.orgUsers && i.orgUsers.length>0)
+            res = res.concat(...i.orgUsers)
           }
           t.form.txlUsers = res.map(i=>i.id)
         }else{
           t.form.txlUsers = []
         }
       },
-
-			//选择子部门部分
-			onChanges(value,label,extra) {
+      checkTxlChange2(e) {
         const t = this
-        if(t.form.receiver.length == 0){
-          t.checkAll = false
-        }
-      },
-
-      checkChange(e) {
-        const t = this
-        this.checkAll = !this.checkAll
-        if(t.checkAll == true){
-          t.form.receiver = t.traverseTree(t.areaUsers[0])
+        this.checkTxlAll2 = !this.checkTxlAll2
+        if(t.checkTxlAll2 == true){
+          let res = []
+          for(let i of t.oldAddressBook){
+            if(i.userInfos && i.userInfos.length>0)
+              res = res.concat(...i.userInfos)
+          }
+          t.form.txlUsers = res.map(i=>i.id)
         }else{
-          t.form.receiver = []
-        }
-      },
-
-      //选择平级部门部分
-      handle(selectedItems) {
-        const t = this
-        if(t.form.recipient.length == t.filteredOptions.length){
-          t.checkSlAll = true
-        }else{
-          t.checkSlAll = false
-        }
-      },
-
-      checkSlChange(e) {
-        const t = this
-        t.checkSlAll = !t.checkSlAll
-        if(t.checkSlAll == true){
-          t.form.recipient = t.filteredOptions.map(i=>i.id)
-        }else{
-          t.form.recipient = []
+          t.form.txlUsers = []
         }
       },
 
@@ -389,7 +447,8 @@
             const address = this.form.txlUsers.map((item)=>
                 {
                   this.findUserById(item).recipientType = 3
-                  const {addressBookGroupId,...data} = this.findUserById(item)
+                  const {id,name,phone,company,...rest} = this.findUserById(item)
+                  const data = { id,name,phone,company }
                   data.name = data.name.split('(')[0]
                   return data
                 }
@@ -495,16 +554,29 @@
       },
 
       findUserById(id){
-        for(let i of this.addressBook){
-          if(i.userInfos && i.userInfos.length>0){
-            for(let j of i.userInfos){
-              if(j.id == id){
-                return j
+        if(this.isNewTxl == 1){
+          for(let i of this.addressBook){
+            if(i.orgUsers && i.orgUsers.length>0){
+              for(let j of i.orgUsers){
+                if(j.id == id){
+                  return j
+                }
               }
             }
           }
+          return null
+        }else{
+          for(let i of this.oldAddressBook){
+            if(i.userInfos && i.userInfos.length>0){
+              for(let j of i.userInfos){
+                if(j.id == id){
+                  return j
+                }
+              }
+            }
+          }
+          return null
         }
-        return null
       },
 
       // 将树状数据所有id和name放入对象数组
diff --git a/src/views/Admin/responsor.vue b/src/views/Admin/responsor.vue
new file mode 100644
index 0000000..d407693
--- /dev/null
+++ b/src/views/Admin/responsor.vue
@@ -0,0 +1,338 @@
+<template>
+  <div class="inner">
+    <a-row type="flex" justify="space-between" style="margin-bottom: 20px">
+      <a-col :span="4" v-if="unittype && unittype !== null">
+        <a-button type="primary" @click="editData('add',{})">新增用户</a-button>
+      </a-col>
+      <a-col :span="20">
+        <a-row type="flex" :gutter="14">
+          <a-col :span="6">
+            <a-select v-model="search.searchParams.peerRecipientGroupId" placeholder="选择分组" style="width: 100%" @change="handleChange" allowClear show-search :filter-option="filterOption">
+              <a-select-option v-for="item in groupData" :value="item.id" :key="item.id">{{item.name}}</a-select-option>
+            </a-select>
+          </a-col>
+          <a-col :span="6">
+            <a-input v-model="search.searchParams.company" placeholder="单位名称" style="width: 100%"/>
+          </a-col>
+          <a-col :span="6" v-if="unittype == null || !unittype">
+            <a-cascader :options="areaData" v-model="areaVal" placeholder="所属区域" expandTrigger="hover" :fieldNames="fieldNames" changeOnSelect @change="onChange" style="width: 100%"/>
+          </a-col>
+          <a-col :span="6">
+            <a-button type="primary" @click="getUserList" v-preventReClick="1500">查询</a-button>
+            <a-button style="margin-left: 12px" @click="resetSearch">重置</a-button>
+            <a-button type="danger" style="margin-left: 12px" @click="delBySet">批量删除</a-button>
+          </a-col>
+        </a-row>
+      </a-col>
+    </a-row>
+    <div class="table-cont">
+      <a-table :columns="columns" :data-source="tableData" :pagination="pagination" :rowKey="record=>record.id" bordered :row-selection="{ selectedRowKeys: selectedRowKeys, onChange: onSelectChange }">
+        <template #unittype="unittype">
+          <a-tag
+              :color="unittype === 1 ? 'purple' : unittype === 2 ? 'blue' : unittype === 3 ? 'cyan' : 'green'"
+          >
+            {{ unittype==1?'省级':unittype==2?'地(市、州)级':unittype==3?'区县级':unittype==4?'村(乡、镇)级':'管理员' }}
+          </a-tag>
+        </template>
+        <template #area="text,row">
+          <span v-if="row.province !== null && row.province !== ''">{{row.province}}</span>
+          <span v-if="row.city !== null && row.city !== ''">-{{row.city}}</span>
+          <span v-if="row.area !== null && row.area !== ''">-{{row.area}}</span>
+          <span v-if="row.town !== null && row.town !== ''">-{{row.town}}</span>
+        </template>
+        <template #action="action,row">
+          <a-button type="link" @click="editData('edit',row)">编辑</a-button>
+          <a-button type="link" class="delBtn" @click="delData(row)">删除</a-button>
+        </template>
+      </a-table>
+    </div>
+    <same-level-mod ref="sameLevelMod" @refresh="getUserList"></same-level-mod>
+  </div>
+</template>
+
+<script>
+import {delRecipient, delRecipientBatch, delUser, getRecipient, getSameLevelGroupList, getUser} from '@/api/user'
+import sameLevelMod from "@/views/Admin/components/sameLevelMod"
+import {getUserInfo} from "@/util/storage";
+import {getDistrictInfo} from "@/api/login";
+export default {
+  name: 'sameLevel',
+  components: {
+    sameLevelMod
+  },
+  data () {
+    return {
+      areaVal: [],
+      unittype: null,
+      districtId: null,
+      search:{
+        pageIndex: 1,
+        pageSize: 10,
+        searchParams:{
+          company: '',
+          province: '',
+          city: '',
+          area: '',
+          town: '',
+          peerRecipientGroupId: undefined
+        }
+      },
+      selectedRowKeys: [],
+      columns:[
+        {
+          title: '单位名称',
+          dataIndex: 'company',
+          key: 'company'
+        },
+        {
+          title: '接收人姓名',
+          dataIndex: 'recipientName',
+          key: 'recipientName'
+        },
+        {
+          title: '所属分组',
+          dataIndex: 'peerRecipientGroupName',
+          key: 'peerRecipientGroupName'
+        },
+        {
+          title: '手机号码',
+          dataIndex: 'phone',
+          key: 'phone'
+        },
+        {
+          title: '级别',
+          dataIndex: 'unittype',
+          // key: 'unittype',
+          scopedSlots: { customRender: 'unittype' }
+        },
+        {
+          title: '行政区划',
+          dataIndex: 'area',
+          // key: 'area',
+          scopedSlots: { customRender: 'area' }
+        },
+        {
+          title: '操作',
+          width: '12%',
+          key: 'action',
+          scopedSlots: { customRender: 'action' }
+        },
+      ],
+      tableData: [],
+      groupData: [],
+      pagination: {
+        current: 1,
+        defaultCurrent: 1,
+        defaultPageSize: 10,
+        total: 0,
+        onChange: ( page, pageSize ) => this.onPageChange(page,pageSize),
+        showTotal: total => `共 ${total} 条`
+      },
+      areaData: [],
+      fieldNames:{
+        label: 'name',
+        value: 'id',
+        children: 'children'
+      }
+    }
+  },
+  created() {
+    const t = this
+    t.groupData = []
+    t.unittype = getUserInfo().unittype
+    t.districtId = getUserInfo().districtId
+    t.getGroupList()
+    t.getUserList()
+    t.getDistrictInfo()
+  },
+  methods:{
+    async getUserList(){
+      const t = this
+      if(t.search.searchParams.province == '' && t.search.searchParams.city == '' && t.search.searchParams.area == '' && t.search.searchParams.company == '' && t.search.searchParams.peerRecipientGroupId == undefined){
+        const {searchParams,...data} = t.search
+        const res = await getRecipient(data)
+        if(res.data.code == 100){
+          t.tableData = res.data.data
+          t.pagination.total = res.data.total
+        }else{
+          t.$message.warning(res.data.msg);
+        }
+      }else{
+        const res = await getRecipient(t.search)
+        if(res.data.code == 100){
+          t.tableData = res.data.data
+          t.pagination.total = res.data.total
+        }else{
+          t.$message.warning(res.data.msg);
+        }
+      }
+    },
+
+    async getDistrictInfo(){
+      let res = await getDistrictInfo()
+      if(res.data.code == 100){
+        this.areaData = res.data.data
+      } else {
+        this.$message.warning(res.data.msg);
+      }
+    },
+
+    async getGroupList() {
+      const t = this
+      const res = await getSameLevelGroupList();
+      if(res.data.code == 100){
+        if(res.data.data){
+          let arr = res.data.data
+          t.groupData = arr.concat([{id: -1, name: '未分类'}])
+        }else{
+          t.groupData = [{
+            id: -1,
+            name: '未分类'
+          }]
+        }
+      }else{
+        this.$message.error(res.data.msg)
+      }
+    },
+    resetSearch(){
+      const t = this
+      t.areaVal = []
+      t.search = {
+        pageIndex: 1,
+        pageSize: 10,
+        searchParams:{
+          company: '',
+          province: '',
+          city: '',
+          area: '',
+          town: '',
+          peerRecipientGroupId: undefined
+        }
+      }
+      t.getUserList()
+    },
+
+    editData(type,data){
+      const t = this
+      t.$refs.sameLevelMod.openDialog(type,data,t.groupData)
+      t.$refs.sameLevelMod.areaData = t.areaData
+      t.$refs.sameLevelMod.form.unittype = t.unittype
+      t.$refs.sameLevelMod.form.districtId = t.districtId
+    },
+
+    filterOption(input, option) {
+      return (
+          option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
+      );
+    },
+
+    async delData(row){
+      const t = this
+      this.$confirm({
+        title: '提示',
+        content: h => <div>是否删除该条用户信息?</div>,
+        cancelText: '取消',
+        okText: '确认',
+        centered: true,
+        onOk() {
+          delRecipient(row.id).then(res=>{
+            if(res.data.code == 100){
+              t.$message.success('删除用户信息成功');
+              t.getUserList()
+            }else{
+              t.$message.warning(res.data.msg);
+            }
+          })
+        },
+        onCancel() {
+          console.log('Cancel');
+        },
+      });
+    },
+
+    // 根据id查对象
+    findCodeById(data,value) {
+      for (const node of data) {
+        if (node.id === value) {
+          return node;
+        }
+        if (node.children) {
+          const foundNode = this.findCodeById(node.children, value);
+          if (foundNode) {
+            return foundNode;
+          }
+        }
+      }
+      return null;
+    },
+
+    async delBySet(){
+      const t = this
+      this.$confirm({
+        title: '提示',
+        content: h => <div>是否删除所选用户信息?</div>,
+        cancelText: '取消',
+        okText: '确认',
+        centered: true,
+        onOk() {
+          delRecipientBatch(t.selectedRowKeys.join(',')).then(res=>{
+            if(res.data.code == 100){
+              t.$message.success('删除用户信息成功');
+              t.getUserList()
+              t.selectedRowKeys = []
+            }else{
+              t.$message.warning(res.data.msg);
+            }
+          })
+        },
+        onCancel() {
+          console.log('Cancel');
+        },
+      });
+    },
+
+    onPageChange(page, pageSize) {
+      const t= this
+      t.pagination.current = page
+      t.search.pageIndex = page
+      t.getUserList()
+    },
+    onChange(value) {
+      const t = this
+      t.search.searchParams = {
+        company: '',
+        province: '',
+        city: '',
+        area: '',
+        town: '',
+        peerRecipientGroupId: undefined
+      }
+      if(value[0]){
+        t.search.searchParams.province = t.findCodeById(t.areaData,value[0]).name
+      }
+      if(value[1]){
+        t.search.searchParams.city = t.findCodeById(t.areaData,value[1]).name
+      }
+      if(value[2]){
+        t.search.searchParams.area = t.findCodeById(t.areaData,value[2]).name
+      }
+      if(value[3]){
+        t.search.searchParams.town = t.findCodeById(t.areaData,value[3]).name
+      }
+    },
+    handleChange(value) {
+      console.log(`selected ${value}`);
+      this.getUserList()
+    },
+    onSelectChange(selectedRowKeys) {
+      this.selectedRowKeys = selectedRowKeys;
+    },
+  }
+}
+</script>
+
+<style lang="less" scoped>
+.delBtn{
+  color: @danger
+}
+</style>

--
Gitblit v1.9.2