已添加4个文件
已修改18个文件
1337 ■■■■■ 文件已修改
admin/src/api/business/company.js 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/api/business/member.js 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/components/business/OperaInternalCompanyWindow.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/business/categoryJkBanner.vue 91 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/business/categoryJkLine.vue 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/business/inoutRecord.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/business/internalCompany.vue 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/business/internalMember.vue 34 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/task/index.vue 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/vehicle/category.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/vehicle/components/OperaCategoryWindow.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/system_service/pom.xml 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/system_service/src/main/java/com/doumee/core/utils/Constants.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_admin/src/main/java/com/doumee/api/business/CompanyController.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_admin/src/main/java/com/doumee/cloud/admin/CompanyCloudController.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_service/src/main/java/com/doumee/core/dingTalk/DingTalk.java 369 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_service/src/main/java/com/doumee/core/dingTalk/DingTalkStream.java 96 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/Category.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_service/src/main/java/com/doumee/service/business/CompanyService.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/CategoryServiceImpl.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/CompanyServiceImpl.java 312 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/MemberServiceImpl.java 248 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/api/business/company.js
@@ -37,6 +37,9 @@
export function companySync (data) {
  return request.post('/visitsAdmin/cloudService/business/company/syncAll', data)
}
export function companySyncDingding (data) {
  return request.post('/visitsAdmin/cloudService/business/company/syncAllDingding', data)
}
// åˆ†é¡µæŸ¥è¯¢
export function companyGetList (data) {
  return request.post('/visitsAdmin/cloudService/business/company/page', data)
admin/src/api/business/member.js
@@ -19,10 +19,13 @@
    trim: true
  })
}
// éƒ¨é—¨ä¿¡æ¯åŒæ­¥
// ä¿¡æ¯åŒæ­¥
export function memberSync (data) {
  return request.post('/visitsAdmin/cloudService/business/member/syncAll', data)
}
export function memberSyncDingding (data) {
  return request.post('/visitsAdmin/cloudService/business/member/syncAllDingding', data)
}
export function delHkForce (data) {
  return request.post('/visitsAdmin/cloudService/business/member/delHkForce', data)
}
admin/src/components/business/OperaInternalCompanyWindow.vue
@@ -18,10 +18,10 @@
            <el-form-item label="排序码" prop="sortnum">
                <el-input v-model="form.sortnum" placeholder="请输入排序码" v-trim/>
            </el-form-item>
          <el-form-item label="组织类型" prop="type" v-if="(editType === 'edit' && parentId) || (editType === 'add')">
          <el-form-item label="组织类型" prop="type" v-if="(editType === 'edit' && parentId) || (editType === 'add')" >
            <el-radio-group v-model="form.type" :disabled="(editType === 'edit') || (!!(editType === 'add' && parentId))">
              <el-radio :label="0">相关方组织</el-radio>
              <el-radio :label="1">内部组织</el-radio>
<!--              <el-radio :label="1">内部组织</el-radio>-->
            </el-radio-group>
          </el-form-item>
        </el-form>
admin/src/views/business/categoryJkBanner.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,91 @@
<template>
  <TableLayout :permissions="['business:category:query']">
    <!-- æœç´¢è¡¨å• -->
    <el-form ref="searchForm" slot="search-form" :model="searchForm" label-width="120px" inline>
      <el-form-item label="广告名称" prop="name">
        <el-input v-model="searchForm.name" clearable placeholder="请输入广告名称" @keypress.enter.native="search"></el-input>
      </el-form-item>
      <section>
        <el-button type="primary" @click="search">搜索</el-button>
        <el-button @click="reset">重置</el-button>
      </section>
    </el-form>
    <!-- è¡¨æ ¼å’Œåˆ†é¡µ -->
    <template v-slot:table-wrap>
      <ul class="toolbar" v-permissions="['business:category:create','business:category:delete']">
        <li><el-button type="primary" @click="$refs.OperaCategoryFileWindow.open('新建广告')" icon="el-icon-plus" v-permissions="['business:category:create']">新建</el-button></li>
        <li><el-button type="danger" @click="deleteByIdInBatch" icon="el-icon-delete" v-permissions="['business:category:delete']">批量删除</el-button></li>
      </ul>
      <el-table
          :height="tableHeightNew"
          v-loading="isWorking.search"
          :data="tableData.list"
          stripe
          @selection-change="handleSelectionChange"
      >
        <el-table-column type="selection" width="55"></el-table-column>
        <el-table-column prop="name" show-overflow-tooltip label="广告" min-width="120px"></el-table-column>
        <el-table-column prop="imgurl" show-overflow-tooltip label="" min-width="120px">
          <template slot-scope="{row}">
            <el-image v-if="row.imgurlFull" style="width: 60px; height: 60px" :src="row.imgurlFull"
                      :preview-src-list="[row.imgurlFull]">
            </el-image>
          </template>
        </el-table-column>
        <el-table-column prop="sortnum" label="排序码"  min-width="70px"></el-table-column>
        <el-table-column prop="editDate" label="操作时间" width="160px"></el-table-column>
        <el-table-column
            v-if="containPermissions(['business:category:update', 'business:category:delete' ])"
            label="操作"
            min-width="140"
            fixed="right"
        >
          <template slot-scope="{row}">
            <el-button type="text" icon="el-icon-edit" @click="$refs.OperaCategoryFileWindow.open('编辑广告',row)" v-permissions="['business:category:update']">编辑</el-button>
            <el-button  type="text"  icon="el-icon-delete" @click="deleteById(row)" style="color: red" v-permissions="['business:category:delete']">删除</el-button>
          </template>
        </el-table-column>
      </el-table>
      <pagination
          @size-change="handleSizeChange"
          @current-change="handlePageChange"
          :pagination="tableData.pagination"
      >
      </pagination>
    </template>
    <!-- æ–°å»º/修改 -->
    <OperaCategoryFileWindow ref="OperaCategoryFileWindow" @success="handlePageChange"/>
  </TableLayout>
</template>
<script>
import BaseTable from '@/components/base/BaseTable'
import TableLayout from '@/layouts/TableLayout'
import Pagination from '@/components/common/Pagination'
import OperaCategoryFileWindow from '@/components/business/OperaCategoryFileWindow'
export default {
  name: 'areaSet',
  extends: BaseTable,
  components: { TableLayout, Pagination, OperaCategoryFileWindow },
  data () {
    return {
      // æœç´¢
      searchForm: {
        name: '',
        type: 4
      }
    }
  },
  created () {
    this.config({
      module: '广告',
      api: '/business/category',
      'field.id': 'id',
      'field.main': 'id'
    })
    this.search()
  },
  methods: {
  }
}
</script>
admin/src/views/business/categoryJkLine.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,84 @@
<template>
  <TableLayout :permissions="['business:category:query']">
    <!-- æœç´¢è¡¨å• -->
    <el-form ref="searchForm" slot="search-form" :model="searchForm" label-width="120px" inline>
      <el-form-item label="主线路名称" prop="name">
        <el-input v-model="searchForm.name" clearable placeholder="请输入主线路名称" @keypress.enter.native="search"></el-input>
      </el-form-item>
      <section>
        <el-button type="primary" @click="search">搜索</el-button>
        <el-button @click="reset">重置</el-button>
      </section>
    </el-form>
    <!-- è¡¨æ ¼å’Œåˆ†é¡µ -->
    <template v-slot:table-wrap>
      <ul class="toolbar" v-permissions="['business:category:create','business:category:delete']">
        <li><el-button type="primary" @click="$refs.OperaCategoryFileWindow.open('新建主线路')" icon="el-icon-plus" v-permissions="['business:category:create']">新建</el-button></li>
        <li><el-button type="danger" @click="deleteByIdInBatch" icon="el-icon-delete" v-permissions="['business:category:delete']">批量删除</el-button></li>
      </ul>
      <el-table
          :height="tableHeightNew"
          v-loading="isWorking.search"
          :data="tableData.list"
          stripe
          @selection-change="handleSelectionChange"
      >
        <el-table-column type="selection" width="55"></el-table-column>
        <el-table-column prop="name" show-overflow-tooltip label="主线路" min-width="120px"></el-table-column>
        <el-table-column prop="sortnum" label="排序码"  min-width="70px"></el-table-column>
        <el-table-column prop="editDate" label="操作时间" width="160px"></el-table-column>
        <el-table-column
            v-if="containPermissions(['business:category:update', 'business:category:delete' ])"
            label="操作"
            min-width="140"
            fixed="right"
        >
          <template slot-scope="{row}">
            <el-button type="text" icon="el-icon-edit" @click="$refs.OperaCategoryFileWindow.open('编辑主线路',row)" v-permissions="['business:category:update']">编辑</el-button>
            <el-button  type="text"  icon="el-icon-delete" @click="deleteById(row)" style="color: red" v-permissions="['business:category:delete']">删除</el-button>
          </template>
        </el-table-column>
      </el-table>
      <pagination
          @size-change="handleSizeChange"
          @current-change="handlePageChange"
          :pagination="tableData.pagination"
      >
      </pagination>
    </template>
    <!-- æ–°å»º/修改 -->
    <OperaCategoryFileWindow ref="OperaCategoryFileWindow" @success="handlePageChange"/>
  </TableLayout>
</template>
<script>
import BaseTable from '@/components/base/BaseTable'
import TableLayout from '@/layouts/TableLayout'
import Pagination from '@/components/common/Pagination'
import OperaCategoryFileWindow from '@/components/business/OperaCategoryFileWindow'
export default {
  name: 'areaSet',
  extends: BaseTable,
  components: { TableLayout, Pagination, OperaCategoryFileWindow },
  data () {
    return {
      // æœç´¢
      searchForm: {
        name: '',
        type: 4
      }
    }
  },
  created () {
    this.config({
      module: '主线路',
      api: '/business/category',
      'field.id': 'id',
      'field.main': 'id'
    })
    this.search()
  },
  methods: {
  }
}
</script>
admin/src/views/business/inoutRecord.vue
@@ -162,8 +162,8 @@
        { key: 1, name: '外协运输车辆' },
        { key: 2, name: '市公司卸货车辆' },
        { key: 3, name: '加工烟卸货车辆' },
        { key: 4, name: '物流公务用车' },
        { key: 5, name: '物流货运车辆' },
        { key: 4, name: '自有公务车' },
        { key: 5, name: '自有货运车辆' },
        { key: 6, name: '未知车辆' }
      ]
    }
admin/src/views/business/internalCompany.vue
@@ -25,6 +25,8 @@
            v-permissions="['business:company:sort']">下移</el-button></li>
        <li><el-button type="primary" v-permissions="['business:company:sync']" :loading="loading"
            @click="synchronous()">同步</el-button></li>
        <li><el-button type="primary" v-permissions="['business:company:create']" :loading="loading"
            @click="synchronousDingding()">同步钉钉</el-button></li>
      </ul>
      <el-table :max-height="tableHeight" v-loading="isWorking.search" :data="list" stripe
        :tree-props="{ children: 'childList', hasChildren: 'hasChildren' }" row-key="id"
@@ -45,7 +47,7 @@
          <template slot-scope="{row}">
            <el-button type="text"
              @click="$refs.OperaInternalCompanyWindow.open('编辑企业信息', { id: row.parentId, name: row.parentName, type: row.parentType, companyPath: row.parentCompanyPath }, row, 'edit')"
              icon="el-icon-edit" v-permissions="['business:company:update']">编辑</el-button>
              icon="el-icon-edit" v-permissions="['business:company:update']" v-if="row.type ==0">编辑</el-button>
            <el-button type="text" @click="$refs.OperaInternalCompanyWindow.open('新建子级', row, null, 'add')"
              icon="el-icon-plus">新建子级</el-button>
            <el-button type="text" @click="deleteById(row)" style="color: red" icon="el-icon-delete"
@@ -62,7 +64,7 @@
<script>
import BaseTable from '@/components/base/BaseTable'
import TableLayout from '@/layouts/TableLayout'
import { companySync, sort } from '@/api/business/company'
import { companySync,companySyncDingding, sort } from '@/api/business/company'
import OperaInternalCompanyWindow from '@/components/business/OperaInternalCompanyWindow'
export default {
  name: 'internalCompany',
@@ -129,6 +131,24 @@
        })
        .catch(() => { })
    },
    async synchronousDingding() {
      this.$dialog.actionConfirm('该操作将系统清空已有内部组织信息,您确认同步全部信息吗?', '操作确认提醒')
        .then(() => {
          this.loading = true
          companySyncDingding({})
            .then(res => {
              this.$tip.apiSuccess(res || '同步成功')
              this.search()
            })
            .catch(e => {
              this.$tip.apiFailed(e)
            })
            .finally(() => {
              this.loading = false
            })
        })
        .catch(() => { })
    },
    // æŽ’序
    sort(direction) {
      if (this.sorting) {
admin/src/views/business/internalMember.vue
@@ -66,13 +66,15 @@
      <ul class="toolbar" v-permissions="['business:member:delete', 'business:member:create,business:empower:create']">
        <li><el-button type="primary" v-permissions="['business:member:sync']" :loading="loading"
            @click="synchronous()">同步</el-button></li>
        <li><el-button type="primary"
        <li><el-button type="primary" v-permissions="['business:member:create']" :loading="loading"
            @click="synchronousDingding()">同步钉钉</el-button></li>
<!--        <li><el-button type="primary"
            @click="add" icon="el-icon-plus"
            v-permissions="['business:member:create']">新建员工</el-button></li>
        <li><el-button type="primary" @click="$refs.OperaMemberImportWindow.open('人员导入', searchForm.companyType)"
            icon="el-icon-plus" v-permissions="['business:member:create']">人员导入</el-button></li>
        <li><el-button type="danger" @click="deleteByIdInBatch" icon="el-icon-delete"
            v-permissions="['business:member:delete']">批量删除</el-button></li>
            v-permissions="['business:member:delete']">批量删除</el-button></li>-->
        <li><el-button type="primary" v-permissions="['business:empower:create']"
            @click="startEmpowerBatch()">下发授权</el-button></li>
        <li style="float: right">
@@ -183,8 +185,7 @@
          v-if="containPermissions(['business:member:update', 'business:member:delete', 'business:empower:create'])"
          label="操作" min-width="280">
          <template slot-scope="{row}">
            <el-button type="text" icon="el-icon-edit" @click="edit(row)"
              v-permissions="['business:member:update']">编辑</el-button>
           <el-button type="text" icon="el-icon-edit" @click="edit(row)"  v-permissions="['business:member:update']">编辑</el-button>
            <el-button type="text" icon="el-icon-plus" @click="empower(row.id)"
              v-permissions="['business:empower:create']">重新授权</el-button>
            <el-button type="text" :loading="heading" style="color: red" icon="el-icon-delete"
@@ -192,8 +193,8 @@
              v-permissions="['business:member:head']">取消主管</el-button>
            <el-button type="text" :loading="heading" icon="el-icon-edit" @click="updateHead(row, 1)"
              v-if="row.headStatus == 0" v-permissions="['business:member:head']">设为主管</el-button>
            <el-button type="text" icon="el-icon-delete" @click="deleteById(row)" style="color: red"
              v-permissions="['business:member:delete']">删除</el-button>
<!--            <el-button type="text" icon="el-icon-delete" @click="deleteById(row)" style="color: red"
              v-permissions="['business:member:delete']">删除</el-button>-->
          </template>
        </el-table-column>
      </el-table>
@@ -219,7 +220,7 @@
import OperaMemberImportWindow from '@/components/business/OperaMemberImportWindow'
import { fetchList } from '@/api/business/company'
import { allList } from '@/api/business/position'
import { memberSync, roleAuth, updateCanVisit, updateHead, updateWorkStatus } from '@/api/business/member'
import { memberSync,memberSyncDingding, roleAuth, updateCanVisit, updateHead, updateWorkStatus } from '@/api/business/member'
export default {
  name: 'internalMember',
  extends: BaseTable,
@@ -369,6 +370,25 @@
        })
        .catch(() => { })
    },
    // åŒæ­¥ä¿¡æ¯
    async synchronousDingding() {
      this.$dialog.actionConfirm('该操作降触发全员信息更新和重新下发!请谨慎操作', '您确认全量同步内部人员信息吗?')
        .then(() => {
          this.loading = true
          memberSyncDingding({})
            .then(res => {
              this.$tip.apiSuccess(res || '同步成功')
              this.search()
            })
            .catch(e => {
              this.$tip.apiFailed(e)
            })
            .finally(() => {
              this.loading = false
            })
        })
        .catch(() => { })
    },
    async updateHead(row, type) {
      this.$dialog.actionConfirm('您确认进行当前操作吗?', '部门主管设置操作提示')
        .then(() => {
admin/src/views/task/index.vue
@@ -118,8 +118,8 @@
              { label: '访客申请', value: '0' },
              { label: '访客报备', value: '1' },
              { label: '用车申请', value: '2' },
              { label: '隐患随手拍', value: '3' },
              { label: '物流车申请', value: '6' }
              // { label: '隐患随手拍', value: '3' },
              // { label: '物流车申请', value: '6' }
            ]
          },
          {
@@ -149,8 +149,8 @@
        { name: '访客申请', id: 0 },
        { name: '访客报备', id: 1 },
        { name: '用车申请', id: 2 },
        { name: '隐患随手拍', id: 3 },
        { name: '物流车申请', id: 6 }
        // { name: '隐患随手拍', id: 3 },
        // { name: '物流车申请', id: 6 }
      ]
    }
  },
admin/src/views/vehicle/category.vue
@@ -30,8 +30,8 @@
                      <span  v-else-if="row.bizType ==1">外协运输车辆</span>
                      <span  v-else-if="row.bizType ==2">市公司卸货车辆</span>
                      <span  v-else-if="row.bizType ==3">加工烟卸货车辆</span>
                      <span  v-else-if="row.bizType ==4">物流公务用车</span>
                      <span  v-else-if="row.bizType ==5">物流货运车辆</span>
                      <span  v-else-if="row.bizType ==4">自有公务车</span>
                      <span  v-else-if="row.bizType ==5">自有货运车辆</span>
                      <span  v-else >-</span>
                    </template>
              </el-table-column>
admin/src/views/vehicle/components/OperaCategoryWindow.vue
@@ -50,8 +50,8 @@
        { key: 1, name: '外协运输车辆' },
        { key: 2, name: '市公司卸货车辆' },
        { key: 3, name: '加工烟卸货车辆' },
        { key: 4, name: '物流公务用车' },
        { key: 5, name: '物流货运车辆' }
        { key: 4, name: '自有公务车' },
        { key: 5, name: '自有货运车辆' }
      ],
      // éªŒè¯è§„则
      rules: {
server/system_service/pom.xml
@@ -137,7 +137,12 @@
        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>dingtalk</artifactId>
            <version>1.3.54</version>
            <version>2.2.25</version>
        </dependency>
        <dependency>
            <groupId>com.dingtalk.open</groupId>
            <artifactId>app-stream-client</artifactId>
            <version>1.3.7</version>
        </dependency>
        <dependency>
            <groupId>com.aliyun</groupId>
server/system_service/src/main/java/com/doumee/core/utils/Constants.java
@@ -26,6 +26,8 @@
    public static final int ZERO = 0 ;
    public static final int ONE = 1 ;
    public static final int TWO = 2 ;
    public static final Integer DD_STATUS_SUCCESS_CODE = 200 ;
    public static final Long DD_ERR_CODE = 0L ;
    public static final String HK_PARAM ="HK_PARAM" ;
    public static final String HK_WEBSITE_DOMAIN_URL ="HK_WEBSITE_DOMAIN_URL" ;
    public static final String LED_CONTENT_SPEED ="LED_CONTENT_SPEED" ;
@@ -158,6 +160,7 @@
    public static final String PRESSURE_LEVEL_UNIT = "PRESSURE_LEVEL_UNIT";
    public static final String LIQUID_LEVEL_UNIT ="LIQUID_LEVEL_UNIT" ;
    public static final String OUT_HY_LOT_TOTAL ="OUT_HY_LOT_TOTAL" ;
    public static final String BANNER_IMG ="BANNER_IMG" ;
    public static  boolean DEALING_HK_SYNCPRIVILEGE= false;
    public static  boolean DEALING_HK_SYNCDEVICE = false;
@@ -492,6 +495,10 @@
    public static final String HOME_IMAGE ="HOME_IMAGE";
    public static final String DD_TALK ="DD_TALK";
    public static final String APP_KEY ="APP_KEY";
    public static final String APP_SECRET ="APP_SECRET";
    public static final String ACCESS_TOKEN ="ACCESS_TOKEN";
server/visits/dmvisit_admin/src/main/java/com/doumee/api/business/CompanyController.java
@@ -13,6 +13,7 @@
import com.doumee.service.business.CompanyService;
import com.doumee.service.business.ext.ERPSyncService;
import com.doumee.service.business.impl.hksync.fhk.HkSyncOrgUserFromHKServiceImpl;
import com.taobao.api.ApiException;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
@@ -163,8 +164,6 @@
    public ApiResponse<List<CompanyDTO>> findCompanyTreePage(Integer type){
        return ApiResponse.success(companyService.findCompanyTreePage(type));
    }
    @ApiOperation("全量部门信息同步")
    @PostMapping("/syncAll")
server/visits/dmvisit_admin/src/main/java/com/doumee/cloud/admin/CompanyCloudController.java
@@ -16,7 +16,9 @@
import com.doumee.service.business.ext.ERPSyncService;
import com.doumee.service.business.impl.hksync.fhk.HkSyncOrgUserFromHKServiceImpl;
import com.doumee.service.business.impl.hksync.fhk.HkSyncOrgUserFromSelfServiceImpl;
import com.taobao.api.ApiException;
import io.swagger.annotations.*;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@@ -176,6 +178,14 @@
        return ApiResponse.success(companyService.findCompanyTreePage(type));
    }
    @ApiOperation("全量部门信息同步 - é’‰é’‰")
    @PostMapping("/syncAllDingding")
//    @CloudRequiredPermission("business:company:sync")
    public ApiResponse syncAllDingding() throws ApiException {
        companyService.syncDDCompany();
        return ApiResponse.success("同步成功");
    }
    @ApiOperation("全量部门信息同步")
server/visits/dmvisit_service/src/main/java/com/doumee/core/dingTalk/DingTalk.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,369 @@
package com.doumee.core.dingTalk;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.dingtalkoauth2_1_0.Client;
import com.aliyun.dingtalkoauth2_1_0.models.GetAccessTokenRequest;
import com.aliyun.dingtalkoauth2_1_0.models.GetAccessTokenResponse;
import com.aliyun.tea.TeaException;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.*;
import com.dingtalk.api.response.*;
import com.doumee.biz.system.SystemDictDataBiz;
import com.doumee.core.constants.ResponseStatus;
import com.doumee.core.exception.BusinessException;
import com.doumee.core.utils.Constants;
import com.doumee.dao.business.dao.CompanyMapper;
import com.doumee.dao.business.model.Company;
import com.doumee.dao.system.model.SystemDictData;
import com.doumee.service.business.CompanyService;
import com.github.xiaoymin.knife4j.core.util.CollectionUtils;
import com.taobao.api.ApiException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.stream.Collectors;
/**
 * Created by IntelliJ IDEA.
 *
 * @Author : Rk
 * @create 2025/9/24 16:25
 */
@Slf4j
@Service
public class DingTalk {
    @Autowired
    private SystemDictDataBiz systemDictDataBiz;
    @Autowired
    private CompanyMapper companyMapper;
    /**
     * ä½¿ç”¨ Token åˆå§‹åŒ–账号Client
     * @return Client com.aliyun.dingtalkoauth2_1_0.
     * @throws Exception
     */
    public static Client createClient() throws Exception {
        com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config();
        config.protocol = "https";
        config.regionId = "central";
        return new Client(config);
    }
    public void updTokenInfo() throws Exception {
        String appKey  =  systemDictDataBiz.queryByCode(Constants.DD_TALK,Constants.APP_KEY).getCode();
        String appSecret  = systemDictDataBiz.queryByCode(Constants.DD_TALK,Constants.APP_SECRET).getCode();
        Client client = DingTalk.createClient();
        GetAccessTokenRequest getAccessTokenRequest = new GetAccessTokenRequest()
                .setAppKey(appKey)
                .setAppSecret(appSecret);
        try {
            GetAccessTokenResponse getAccessTokenResponse = client.getAccessToken(getAccessTokenRequest);
            //返参描述 ä¾‹ï¼š{"body":{"accessToken":"76a248ea72ba3f359b39c9e70073d642","expireIn":7200},"headers":{"access-control-allow-origin":"*","date":"Wed, 24 Sep 2025 08:39:36 GMT","server":"DingTalk/1.0.0","transfer-encoding":"chunked","x-acs-request-id":"9E8AF053-04DD-7031-9766-14DFFB087A79","access-control-allow-headers":"X-Requested-With, X-Sequence, _aop_secret, _aop_signature, x-acs-dingtalk-access-token","connection":"keep-alive","content-type":"application/json;charset=utf-8","access-control-expose-headers":"*","x-acs-trace-id":"96e7cf1f3c0e059779a6d581d4b5fca7"},"statusCode":200}
            if(Constants.equalsInteger(getAccessTokenResponse.statusCode,Constants.DD_STATUS_SUCCESS_CODE)){
                //解析token信息 å­˜å‚¨
                String accessToken = getAccessTokenResponse.getBody().getAccessToken();
                //更新token信息存储
                SystemDictData systemDictData = systemDictDataBiz.queryByCode(Constants.DD_TALK,Constants.ACCESS_TOKEN);
                systemDictData.setCode(accessToken);
                systemDictData.setUpdateTime(new Date());
                systemDictDataBiz.updateByIdNew(systemDictData);
            }
            //更新Token信息
            System.out.println(JSONObject.toJSONString(getAccessTokenResponse));
        } catch (TeaException err) {
            if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) {
                // err ä¸­å«æœ‰ code å’Œ message å±žæ€§ï¼Œå¯å¸®åŠ©å¼€å‘å®šä½é—®é¢˜
                log.error("更新钉钉Token失败:{}" + err.message);
            }
        } catch (Exception _err) {
            TeaException err = new TeaException(_err.getMessage(), _err);
            if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) {
                // err ä¸­å«æœ‰ code å’Œ message å±žæ€§ï¼Œå¯å¸®åŠ©å¼€å‘å®šä½é—®é¢˜
                log.error("更新钉钉Token失败:{}" + err.message);
            }
        }
    }
    /**
     * èŽ·å–é’‰é’‰Token
     * @return
     */
    public String getToken(){
        String accessToken  =  systemDictDataBiz.queryByCode(Constants.DD_TALK,Constants.ACCESS_TOKEN).getCode();
        return accessToken;
    }
    /**
     * å…¨é‡åŒæ­¥ éƒ¨é—¨ä¿¡æ¯
     * æŽ¥å£æ–‡æ¡£åœ°å€ https://open.dingtalk.com/document/orgapp/obtain-the-department-list-v2
     * æœ¬æŽ¥å£åªæ”¯æŒèŽ·å–å½“å‰éƒ¨é—¨çš„ä¸‹ä¸€çº§éƒ¨é—¨åŸºç¡€ä¿¡æ¯ï¼Œä¸æ”¯æŒèŽ·å–å½“å‰éƒ¨é—¨ä¸‹æ‰€æœ‰å±‚çº§å­éƒ¨é—¨
     * @throws ApiException
     */
    public List<OapiV2DepartmentGetResponse.DeptGetResponse>  syncAllDDDepartmentList() throws ApiException {
        DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/department/listsub");
        List<Long> headList = new ArrayList<>();
        headList.add(1L);
        List<OapiV2DepartmentListsubResponse.DeptBaseResponse> deptBaseResponseList = new ArrayList<>();
        List<OapiV2DepartmentListsubResponse.DeptBaseResponse> thisLevelList = getDepartmentList(client,headList);
        deptBaseResponseList.addAll(thisLevelList);
        while (CollectionUtils.isNotEmpty(thisLevelList)){
            headList = thisLevelList.stream().map(i->i.getDeptId()).collect(Collectors.toList());
            thisLevelList = getDepartmentList(client,headList);
            if(CollectionUtils.isNotEmpty(thisLevelList)){
                deptBaseResponseList.addAll(thisLevelList);
            }
        }
        List<OapiV2DepartmentGetResponse.DeptGetResponse> getResponseList = new ArrayList<>();
        if(CollectionUtils.isNotEmpty(deptBaseResponseList)){
            for (OapiV2DepartmentListsubResponse.DeptBaseResponse deptBaseResponse:deptBaseResponseList) {
                OapiV2DepartmentGetResponse.DeptGetResponse deptGetResponse = syncDepartmentInfo(deptBaseResponse.getDeptId());
                getResponseList.add(deptGetResponse);
            }
        }
        return getResponseList;
    }
    /**
     * èŽ·å–éƒ¨é—¨ä¸‹çº§æ•°æ®
     * @param client
     * @param deptIdList
     * @return
     * @throws ApiException
     */
    public List<OapiV2DepartmentListsubResponse.DeptBaseResponse> getDepartmentList
            (DingTalkClient client, List<Long> deptIdList) throws ApiException{
        List<OapiV2DepartmentListsubResponse.DeptBaseResponse> thisLevelList = new ArrayList<>();
        for (Long deptId:deptIdList) {
            OapiV2DepartmentListsubRequest req = new OapiV2DepartmentListsubRequest();
            req.setDeptId(deptId);
            req.setLanguage("zh_CN");
            OapiV2DepartmentListsubResponse rsp = client.execute(req, this.getToken());
            if(rsp.getErrcode().equals(Constants.DD_ERR_CODE)){
                if(CollectionUtils.isNotEmpty(rsp.getResult())){
                    thisLevelList.addAll(rsp.getResult());
                }
            }else{
                throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),rsp.getMessage());
            }
        }
        return thisLevelList;
    }
    /**
     * åˆ›å»ºç»„织部门 æš‚不使用
     * æŽ¥å£æ–‡æ¡£åœ°å€ï¼šhttps://open.dingtalk.com/document/orgapp/create-a-department-v2
     * @param ddParentId é’‰é’‰ä¸Šçº§éƒ¨é—¨ä¸»é”® å¦‚果没有则入null
     * @param name éƒ¨é—¨åç§°
     * @param sn åºå·
     * @param id ç³»ç»Ÿéƒ¨é—¨ä¸»é”®
     * @throws ApiException
     */
    public void pushCreatDepartment(Integer ddParentId,String name,Long sn,Integer id) throws ApiException {
        DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/department/create");
        OapiV2DepartmentCreateRequest req = new OapiV2DepartmentCreateRequest();
        //必入参数
        //如果无父级 åˆ™é»˜è®¤è·Ÿç»„织 1L
        req.setParentId(Objects.isNull(ddParentId)?1L:ddParentId);
        req.setName(name);
        req.setOrder(sn);
        //外部部门字段
        req.setSourceIdentifier(id.toString());
        //默认参数
        req.setHideDept(false);
        req.setOuterDept(false);
        req.setCreateDeptGroup(false);
        OapiV2DepartmentCreateResponse rsp = client.execute(req, getToken());
        if(rsp.getErrcode().equals(Constants.DD_ERR_CODE)){
        }else{
            throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),rsp.getMessage());
        }
        System.out.println(rsp.getBody());
    }
    /**
     * æ›´æ–°ç»„织部门 æš‚不使用
     * æŽ¥å£æ–‡æ¡£åœ°å€ï¼šhttps://open.dingtalk.com/document/orgapp/update-a-department-v2
     * @param deptId é’‰é’‰éƒ¨é—¨ä¸»é”®
     * @param name éƒ¨é—¨åç§°
     * @param parentId çˆ¶çº§é’‰é’‰éƒ¨é—¨ä¸»é”®
     * @param sn åºå·
     * @throws ApiException
     */
    public void pushUpdDepartment(Integer deptId,String name,Integer parentId,Long sn) throws ApiException {
        DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/department/update");
        OapiV2DepartmentUpdateRequest req = new OapiV2DepartmentUpdateRequest();
        req.setDeptId(deptId.longValue());
        //如果无父级 åˆ™é»˜è®¤è·Ÿç»„织 1L
        req.setParentId(Objects.isNull(parentId)?1L:parentId.longValue());
        req.setOrder(sn);
        req.setName(name);
        OapiV2DepartmentUpdateResponse rsp = client.execute(req, getToken());
        if(rsp.getErrcode().equals(Constants.DD_ERR_CODE)){
        }else{
            throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),rsp.getMessage());
        }
    }
    /**
     * åˆ é™¤ç»„织部门 æš‚不使用
     * æŽ¥å£æ–‡æ¡£åœ°å€ï¼šhttps://open.dingtalk.com/document/orgapp/delete-a-department-v2
     * @param deptId é’‰é’‰éƒ¨é—¨ä¸»é”®
     * @throws ApiException
     */
    public void pushDelDepartment(Integer deptId) throws ApiException {
        DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/department/delete");
        OapiV2DepartmentDeleteRequest req = new OapiV2DepartmentDeleteRequest();
        req.setDeptId(deptId.longValue());
        OapiV2DepartmentDeleteResponse rsp = client.execute(req, getToken());
        System.out.println(rsp.getBody());
        if(rsp.getErrcode().equals(Constants.DD_ERR_CODE)){
        }else{
            throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),rsp.getMessage());
        }
    }
    /**
     * èŽ·å–é’‰é’‰éƒ¨é—¨è¯¦æƒ…
     * @param deptId
     * @return
     * @throws ApiException
     */
    public OapiV2DepartmentGetResponse.DeptGetResponse syncDepartmentInfo(Long deptId) throws ApiException {
        DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/department/get");
        OapiV2DepartmentGetRequest req = new OapiV2DepartmentGetRequest();
        req.setDeptId(deptId);
        req.setLanguage("zh_CN");
        OapiV2DepartmentGetResponse rsp = client.execute(req, getToken());
        System.out.println(rsp.getBody());
        if(rsp.getErrcode().equals(Constants.DD_ERR_CODE)){
            return rsp.getResult();
        }else{
            throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),rsp.getMessage());
        }
    }
    public List<OapiV2UserGetResponse.UserGetResponse>  syncAllUserInfo() throws ApiException {
        List<Company> deptList = companyMapper.selectList(new QueryWrapper<Company>().lambda()
                .eq(Company::getIsdeleted,Constants.ZERO)
                .eq(Company::getType,Constants.ONE)
                .isNotNull(Company::getErpId)
        );
        if(CollectionUtils.isEmpty(deptList)){
            return null;
        }
        List<String> allUserIdList = new ArrayList<>();
        DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/user/listid");
        OapiUserListidRequest req = new OapiUserListidRequest();
        for (Company company:deptList) {
            req.setDeptId(Long.valueOf(company.getErpId()));
            OapiUserListidResponse rsp = client.execute(req, getToken());
            if(rsp.getErrcode().equals(Constants.DD_ERR_CODE)){
                if(CollectionUtils.isNotEmpty(rsp.getResult().getUseridList())){
                    allUserIdList.addAll(rsp.getResult().getUseridList());
                }
            }else{
                throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),rsp.getMessage());
            }
        }
        if(CollectionUtils.isEmpty(allUserIdList)){
            return null;
        }
        Set<String> setUserIdList = new HashSet<>(allUserIdList);
        return syncUserInfoList(setUserIdList);
    }
    public List<OapiV2UserGetResponse.UserGetResponse>  syncUserInfoList(Set<String> setUserIdList) throws ApiException {
        List<OapiV2UserGetResponse.UserGetResponse> userList = new ArrayList<>();
        DefaultDingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/get");
        OapiV2UserGetRequest req = new OapiV2UserGetRequest();
        for (String userId:setUserIdList) {
            req.setUserid(userId);
            req.setLanguage("zh_CN");
            OapiV2UserGetResponse rsp = client.execute(req, getToken());
            if(rsp.getErrcode().equals(Constants.DD_ERR_CODE)){
                OapiV2UserGetResponse.UserGetResponse userGetResponse = rsp.getResult();
                userList.add(userGetResponse);
            }else{
                throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),rsp.getMessage());
            }
        }
        return userList;
    }
    public OapiV2UserGetResponse.UserGetResponse syncUserInfo(String userId)throws ApiException {
        DefaultDingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/get");
        OapiV2UserGetRequest req = new OapiV2UserGetRequest();
        req.setUserid(userId);
        req.setLanguage("zh_CN");
        OapiV2UserGetResponse rsp = client.execute(req, getToken());
        if(rsp.getErrcode().equals(Constants.DD_ERR_CODE)){
            OapiV2UserGetResponse.UserGetResponse userGetResponse = rsp.getResult();
            return userGetResponse;
        }else{
            throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),rsp.getMessage());
        }
    }
    public static void main(String[] args) throws Exception {
        String appKey  = "dingkfglaktqmfd2dmo2";//systemDictDataBiz.queryByCode("","").getCode();
        String appSecret  = "0e22TT2s794Yj49Exgvq8nU2ulpXmxlw9ThBh5s-vDv5Cfspv-f8HPmta4cg2evk";//systemDictDataBiz.queryByCode("","").getCode();
        Client client = DingTalk.createClient();
        GetAccessTokenRequest getAccessTokenRequest = new GetAccessTokenRequest()
                .setAppKey(appKey)
                .setAppSecret(appSecret);
        try {
            GetAccessTokenResponse getAccessTokenResponse = client.getAccessToken(getAccessTokenRequest);
            //更新Token信息
            System.out.println(JSONObject.toJSONString(getAccessTokenResponse));
        } catch (TeaException err) {
            if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) {
                // err ä¸­å«æœ‰ code å’Œ message å±žæ€§ï¼Œå¯å¸®åŠ©å¼€å‘å®šä½é—®é¢˜
                log.error("更新钉钉Token失败:{}" + err.message);
            }
        } catch (Exception _err) {
            TeaException err = new TeaException(_err.getMessage(), _err);
            if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) {
                // err ä¸­å«æœ‰ code å’Œ message å±žæ€§ï¼Œå¯å¸®åŠ©å¼€å‘å®šä½é—®é¢˜
                log.error("更新钉钉Token失败:{}" + err.message);
            }
        }
    }
}
server/visits/dmvisit_service/src/main/java/com/doumee/core/dingTalk/DingTalkStream.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,96 @@
package com.doumee.core.dingTalk;
import com.dingtalk.open.app.api.GenericEventListener;
import com.dingtalk.open.app.api.OpenDingTalkStreamClientBuilder;
import com.dingtalk.open.app.api.message.GenericOpenDingTalkEvent;
import com.dingtalk.open.app.api.security.AuthClientCredential;
import com.dingtalk.open.app.stream.protocol.event.EventAckStatus;
import com.doumee.biz.system.SystemDictDataBiz;
import com.doumee.core.utils.Constants;
import com.doumee.dao.business.dao.CompanyMapper;
import com.doumee.dao.business.dao.MemberMapper;
import com.doumee.service.business.CompanyService;
import com.doumee.service.business.MemberService;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.mp.config.WxMpConfigStorage;
import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import shade.com.alibaba.fastjson2.JSONObject;
/**
 * é’‰é’‰ è®¢é˜…事件通知
 *
 * @Author : Rk
 * @create 2025/9/24 17:14
 */
@Slf4j
@Configuration
public class DingTalkStream {
    @Autowired
    private SystemDictDataBiz systemDictDataBiz;
    @Autowired
    private MemberService memberService;
    @Autowired
    private CompanyService companyService;
    @Bean
    public void DingTalkStreamRun()  throws Exception {
        String appKey  =  systemDictDataBiz.queryByCode(Constants.DD_TALK,Constants.APP_KEY).getCode();
        String appSecret  = systemDictDataBiz.queryByCode(Constants.DD_TALK,Constants.APP_SECRET).getCode();
        OpenDingTalkStreamClientBuilder
                .custom()
                .credential(new AuthClientCredential(appKey, appSecret))
                //注册事件监听
                .registerAllEventListener(new GenericEventListener() {
                    @Override
                    public EventAckStatus onEvent(GenericOpenDingTalkEvent event) {
                        try {
                            //事件唯一Id
                            String eventId = event.getEventId();
                            log.error("钉钉推送事件Id:{}"+eventId);
                            //事件类型
                            String eventType = event.getEventType();
                            log.error("钉钉推送事件类型:{}"+eventType);
                            // org_dept_create éƒ¨é—¨æ–°å»º {"timeStamp":"1758783935796","eventId":"0c779adba04143958a3960e8e36bbce5","deptId":[1040735458]}
                            // org_dept_modify éƒ¨é—¨ä¿®æ”¹ {"timeStamp":"1758785791639","eventId":"6c2d8c7a61a7419e8928fda3effb3bf4","deptId":[1040735458]}
                            // org_dept_remove éƒ¨é—¨åˆ é™¤ {"timeStamp":"1758785817760","eventId":"47e289f334e041719ed354052da474de","deptId":[1040735458]}
                            // user_add_org å‘˜å·¥æ·»åŠ 
                            // user_modify_org å‘˜å·¥ä¿®æ”¹  {"timeStamp":"1758786235842","diffInfo":[{"prev":{"extFields":"{}","hiredDate":"2022-03-30","name":"任康","telephone":"145","remark":"","workPlace":"莲花科创园 F401","jobNumber":"","email":"rk@doumee.com"},"curr":{"extFields":"{}","hiredDate":"2022-03-30","name":"任康","telephone":"145","remark":"","workPlace":"莲花科创园 F401","jobNumber":"","email":"rk@doumee.com"},"userid":"1568490244651036"}],"eventId":"e54d8991aed14c669e22e460459433f6","optStaffId":"045831294126209983","userId":["1568490244651036"]}
                            // user_leave_org å‘˜å·¥åˆ é™¤
                            //事件产生时间
                            Long bornTime = event.getEventBornTime();
                            log.error("钉钉推送事件产生时间:{}"+bornTime);
                            //获取事件体
                            JSONObject bizData = event.getData();
                            log.error("钉钉推送事件详情:{}"+bizData);
                            if(eventType.startsWith("org")){
                                companyService.ddPushCompanyInfo(eventType,bizData);
                            }else if(eventType.startsWith("user")){
                            }
                            //处理事件
//                            process(bizData);
                            //消费成功
                            return EventAckStatus.SUCCESS;
                        } catch (Exception e) {
                            //消费失败
                            return EventAckStatus.LATER;
                        }
                    }
                })
                .build().start();
    }
}
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/Category.java
@@ -68,7 +68,7 @@
     //@ExcelColumn(name="图标")
    private String imgurl;
    @ApiModelProperty(value = "类型 0公司类型 1车辆类型")
    @ApiModelProperty(value = "类型 0公司类型 1车辆类型 2资料分类 3钥匙柜终端广告 4交控主线路")
     //@ExcelColumn(name="类型 0公司类型 1车辆类型")
    private Integer type;
    @ApiModelProperty(value = "业务类型 " +
@@ -92,6 +92,8 @@
    @TableField(exist = false)
    @ExcelColumn(name="组合名称",index = 3,width = 20)
    private String groupName;
    @ApiModelProperty(value = "完整图片地址 ")
    private String imgurlFull;
    @ApiModelProperty(value = "子集分类")
    @TableField(exist = false)
server/visits/dmvisit_service/src/main/java/com/doumee/service/business/CompanyService.java
@@ -1,11 +1,14 @@
package com.doumee.service.business;
import com.dingtalk.api.response.OapiV2DepartmentListsubResponse;
import com.doumee.service.business.third.model.LoginUserInfo;
import com.doumee.service.business.third.model.PageData;
import com.doumee.service.business.third.model.PageWrap;
import com.doumee.dao.admin.request.UpdateCompanySortDTO;
import com.doumee.dao.admin.response.CompanyDTO;
import com.doumee.dao.business.model.Company;
import com.taobao.api.ApiException;
import shade.com.alibaba.fastjson2.JSONObject;
import java.util.List;
@@ -126,4 +129,8 @@
    List<Company> companyTree(Integer type);
    void updateSort(UpdateCompanySortDTO dto);
    void ddPushCompanyInfo(String eventType, JSONObject eventData) throws ApiException;
    String syncDDCompany()throws ApiException;
}
server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/CategoryServiceImpl.java
@@ -1,5 +1,6 @@
package com.doumee.service.business.impl;
import com.doumee.biz.system.SystemDictDataBiz;
import com.doumee.core.constants.ResponseStatus;
import com.doumee.core.exception.BusinessException;
import com.doumee.service.business.third.model.LoginUserInfo;
@@ -37,6 +38,8 @@
@Service
public class CategoryServiceImpl implements CategoryService {
    @Autowired
    private SystemDictDataBiz systemDictDataBiz;
    @Autowired
    private CategoryMapper categoryMapper;
@@ -155,6 +158,9 @@
        IPage<Category> page = new Page<>(pageWrap.getPage(), pageWrap.getCapacity());
        QueryWrapper<Category> queryWrapper = new QueryWrapper<>();
        Utils.MP.blankToNull(pageWrap.getModel());
        String prefixUrl = systemDictDataBiz.queryByCode(Constants.FTP,Constants.FTP_RESOURCE_PATH).getCode() +
                systemDictDataBiz.queryByCode(Constants.FTP,Constants.BANNER_IMG).getCode();
        queryWrapper.lambda().eq(Category::getIsdeleted,Constants.ZERO)
                .eq(Objects.nonNull(pageWrap.getModel().getType()),Category::getType,pageWrap.getModel().getType())
                .like(StringUtils.isNotBlank(pageWrap.getModel().getName()),Category::getName,pageWrap.getModel().getName())
@@ -171,6 +177,9 @@
            category.setChildCategoryList(
                    categoryList.stream().filter(i->Constants.equalsInteger(i.getParentId(),category.getId())).collect(Collectors.toList())
            );
            if(StringUtils.isNotBlank(category.getImgurl())){
                category.setImgurlFull(prefixUrl + category.getImgurl());
            }
        }
        return categoryPageData;
server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/CompanyServiceImpl.java
@@ -5,9 +5,15 @@
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.dingtalk.api.response.OapiV2DepartmentGetResponse;
import com.dingtalk.api.response.OapiV2DepartmentListsubResponse;
import com.doumee.biz.system.SystemDictDataBiz;
import com.doumee.config.DataSyncConfig;
import com.doumee.core.constants.ResponseStatus;
import com.doumee.core.dingTalk.DingTalk;
import com.doumee.core.erp.ErpConstants;
import com.doumee.core.erp.model.openapi.request.erp.OrgListRequest;
import com.doumee.core.erp.model.openapi.response.erp.ErpOrgListResponse;
import com.doumee.core.exception.BusinessException;
import com.doumee.core.haikang.model.HKConstants;
import com.doumee.core.haikang.model.param.BaseResponse;
@@ -33,6 +39,7 @@
import com.doumee.dao.system.model.SystemUser;
import com.doumee.service.business.CompanyService;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.taobao.api.ApiException;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
@@ -40,6 +47,8 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import shade.com.alibaba.fastjson2.JSONArray;
import shade.com.alibaba.fastjson2.JSONObject;
import java.util.*;
import java.util.stream.Collectors;
@@ -63,6 +72,9 @@
    @Autowired
    private CompanyJoinMapper companyJoinMapper;
    @Autowired
    private DingTalk dingTalk;
    @Override
    @Transactional(rollbackFor = {BusinessException.class,Exception.class})
@@ -765,7 +777,305 @@
        for (Company updCompany:companyPool) {
            companyMapper.updateById(updCompany);
        }
    }
    // org_dept_create éƒ¨é—¨æ–°å»º {"timeStamp":"1758783935796","eventId":"0c779adba04143958a3960e8e36bbce5","deptId":[1040735458]}
    // org_dept_modify éƒ¨é—¨ä¿®æ”¹ {"timeStamp":"1758785791639","eventId":"6c2d8c7a61a7419e8928fda3effb3bf4","deptId":[1040735458]}
    // org_dept_remove éƒ¨é—¨åˆ é™¤ {"timeStamp":"1758785817760","eventId":"47e289f334e041719ed354052da474de","deptId":[1040735458]}
    @Override
    public void ddPushCompanyInfo(String eventType, JSONObject eventData) throws ApiException {
        JSONArray jsonArray = eventData.getJSONArray("deptId");
        if(jsonArray.isEmpty()){
            return;
        }
        if(eventType.equals("org_dept_remove")){
            //删除对应部门信息
            List<Long> deptIdList = new ArrayList<>();
            for (int i = 0; i < jsonArray.size(); i++) {
                Long deptId = jsonArray.getLong(i);
                 deptIdList.add(deptId);
            }
            if(CollectionUtils.isNotEmpty(deptIdList)){
                syncDelCompany(deptIdList);
            }
        }else if(eventType.equals("org_dept_create")||eventType.equals("org_dept_modify")){
            for (int i = 0; i < jsonArray.size(); i++) {
                Company company  = companyMapper.selectOne(new QueryWrapper<Company>().lambda()
                        .eq(Company::getIsdeleted,Constants.ZERO)
                        .eq(Company::getErpId,jsonArray.getLong(i))
                );
                OapiV2DepartmentGetResponse.DeptGetResponse deptGetResponse = dingTalk.syncDepartmentInfo(jsonArray.getLong(i));
                if(Objects.isNull(company)){
                    getAddCompanyModel(deptGetResponse,company);
                }else{
                    getUpdateCompanyModel(deptGetResponse,company);
                }
            }
        }
    }
    private void doHkDeleteOrg(List<Integer> delIds,List<String> delHkIds,  Date date) {
        if(delHkIds.size() == 0){
            return;
        }
        OrgDelRequest request = new OrgDelRequest();
        request.setIndexCodes( delHkIds.toArray(new String[]{}));
        BaseResponse<List<OrgUpdateFailureResponse>> result =  HKService.delBatchOrg(request);
        if(result !=null && StringUtils.equals(result.getCode(),HKConstants.RESPONSE_SUCCEE)){
            List<String> fIds = new ArrayList<>();
            if(result.getData()!=null){
                for(OrgUpdateFailureResponse r : result.getData()){
                    if(r.getCode().equals("0x00052102")){
                        //不存在的也算删除成功
                        fIds.add(r.getOrgIndexCode());//删除失败的数据集合
                    }
                }
            }
            //标记删除成功的数据(海康对接状态为已同步,,同步失败的仍为待同步,等下一次继续处理,知道全部删除完毕)
            companyMapper.update(null,new UpdateWrapper<Company>().lambda()
                    .set(Company::getHkStatus,Constants.ONE)
                    .set(Company::getHkDate,date)
                    .set(Company::getHkId,null )
                    .in(Company::getId, delIds)
                    .notIn(fIds.size()>0,Company::getHkId, fIds));
            companyMapper.update(null,new UpdateWrapper<Company>().lambda()
                    .set(Company::getHkStatus,Constants.TWO)
                    .set(Company::getHkDate,date)
                    .in(Company::getId, delIds)
                    .in(fIds.size()>0,Company::getHkId, fIds));
        }
    }
    @Override
    public String syncDDCompany() throws ApiException {
        List<OapiV2DepartmentGetResponse.DeptGetResponse> list = dingTalk.syncAllDDDepartmentList();
        if(list !=null && list.size()>0){
            List<Company> addList = new ArrayList<>();
            List<Company> updateList = new ArrayList<>();
            List<Long> delIds = new ArrayList<>();//修改为使用钉钉id  erpId
            List<Company>  allList = companyMapper.selectList(new QueryWrapper<Company>().lambda()
                    .eq(Company::getIsdeleted,Constants.ZERO).eq(Company::getType,Constants.ONE));
            dealCompanyChangeList(list,addList,updateList,delIds,allList);
            if(delIds.size()>0){
                syncDelCompany(delIds);
            }
            return "同步数据:新增【"+addList.size()+"】条,更新【"+updateList.size()+"】条,删除【"+delIds.size()+"】条";
        }else{
            throw  new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "同步钉钉数据为空!");
        }
    }
    private void dealCompanyChangeList(List<OapiV2DepartmentGetResponse.DeptGetResponse> list, List<Company> addList, List<Company> updateList, List<Long> delIds, List<Company> allList) {
        Date date = new Date();
        for(OapiV2DepartmentGetResponse.DeptGetResponse respone : list){
            //根据erpid查询企业信息,判断是新增还是更新
            Company company = findCompanyByERPId(allList,respone.getDeptId().toString());
            if(company == null){
                //如果是新增
                //封装新增组织对象数据
                addList.add(getAddCompanyModel(respone,new Company()));
            }else{
                updateList.add(getUpdateCompanyModel(respone,company));
            }
        }
        if(allList!=null && allList.size()>0){
            for(Company  c : allList){
                if(!isCompanyDeleted(c,list)){
                    delIds.add(Long.valueOf(c.getErpId()));
                }
            }
        }
    }
    /**
     * æ•´ç†é’‰é’‰åŒæ­¥ æ–°å¢žç»„织对象
     * @param deptGetResponse
     * @return
     */
    private Company getAddCompanyModel(OapiV2DepartmentGetResponse.DeptGetResponse deptGetResponse,Company company) {
        return  syncDDAddCompanyModel(deptGetResponse,company);
    }
    /**
     * æ•´ç†é’‰é’‰åŒæ­¥ æ–°å¢ž éœ€è¦ä¿®æ”¹çš„组织对象
     * @param deptGetResponse
     * @param company
     * @return
     */
    private Company getUpdateCompanyModel(OapiV2DepartmentGetResponse.DeptGetResponse deptGetResponse, Company company) {
        return syncDDEditCompanyModel(deptGetResponse,company);
    }
    /**
     * æ ¹æ®ERPID  åˆ¤æ–­æ•°æ®æ˜¯å¦å·²åœ¨é›†åˆé‡Œå­˜åœ¨
     * @param allList
     * @param id
     * @return
     */
    private Company findCompanyByERPId(List<Company> allList, String id) {
        if(allList!=null){
            for(Company com :allList){
                if(StringUtils.equals(com.getErpId(),id)){
                    return com;
                }
            }
        }
        return  null;
    }
    private boolean isCompanyDeleted(Company c, List<OapiV2DepartmentGetResponse.DeptGetResponse> list) {
        for(OapiV2DepartmentGetResponse.DeptGetResponse m : list){
            if(StringUtils.equals(c.getErpId(),m.getDeptId().toString())){
                return  true;
            }
        }
        return false;
    }
    /**
     * æ•´ç† é’‰é’‰åŒæ­¥çš„ ç»„织信息
     * @param deptGetResponse
     * @param company
     * @return
     */
    public Company syncDDAddCompanyModel(OapiV2DepartmentGetResponse.DeptGetResponse deptGetResponse,Company company){
        company = new Company();
        company.setCreateDate(new Date());
        company.setIsdeleted(Constants.ZERO);
        company.setStatus(Constants.ZERO);
        company.setName(deptGetResponse.getName());
        company.setErpId(deptGetResponse.getDeptId().toString());
        company.setErpParentId(deptGetResponse.getParentId().toString());
        company.setSortnum(deptGetResponse.getOrder().intValue());//默认最上面
        company.setType(Constants.ONE);
        String rootOrgId = systemDictDataBiz.queryByCode(Constants.HK_PARAM,Constants.HK_ROOTORG_CODE).getCode();
        company.setCompanyPath(company.getId()+"/");//名称路径
        company.setCompanyNamePath(company.getName());//名称路径
        company.setHkParentId(rootOrgId);
        String idPath = "";
        if(StringUtils.isNotBlank(company.getErpParentId()) && !StringUtils.equals(company.getErpParentId(),Constants.ONE+"")){
            Company parent = companyMapper.selectOne(new QueryWrapper<Company>().lambda().eq(Company::getErpId,company.getErpParentId())
                    .eq(Company::getIsdeleted,Constants.ZERO).last(" limit 1 "));
            if(parent == null || Constants.equalsInteger(parent.getIsdeleted(),Constants.ONE)){
                throw new BusinessException(ResponseStatus.DATA_EXISTS.getCode(), "对不起,父级组织信息不存在~");
            }
//            if(StringUtils.isBlank(parent.getHkId())){
//                throw new BusinessException(ResponseStatus.DATA_EXISTS.getCode(), "对不起,父级组织信息尚未同步下发成功~");
//            }
            if(Objects.nonNull(parent.getType())&&!Constants.equalsInteger(parent.getType(),-1)){
                if(!Constants.equalsInteger(company.getType(),parent.getType())){
                    throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"对不起,组织信息错误");
                }
            }else if(Objects.isNull(parent.getType())){
                throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"对不起,组织信息错误");
            }
            idPath = parent.getCompanyPath();
            company.setHkParentId(parent.getHkId());
            company.setCompanyPath(parent.getCompanyPath()+company.getId()+"/");
            company.setCompanyNamePath(parent.getCompanyNamePath()+"/"+company.getName());
        }
        company.setHkCompanyPath(company.getCompanyNamePath());
        company.setCreateDate(new Date());
        company.setIsdeleted(Constants.ZERO);
        company.setHkStatus(Constants.ZERO);
        company.setStatus(Constants.ZERO);
        company.setHkDate(company.getCreateDate());
        company.setEditDate(company.getCreateDate());
        company.setEditor(company.getCreator());
        company.setPinyin(Constants.getChinesePingyin(company.getName()));
        companyMapper.insert(company);
        company.setHkId(UUID.randomUUID().toString().replace("-",""));
        //下发海康安防平台
        Boolean issueStatus = addHkOrg(company);
        Company com = new Company();
        com.setId(company.getId());
        com.setHkId(issueStatus?company.getHkId():null);
        com.setHkStatus(issueStatus?Constants.ONE:Constants.TWO);
        com.setCompanyPath(idPath+company.getId()+"/");
        companyMapper.updateById(com);
        return company;
    }
    public Company syncDDEditCompanyModel(OapiV2DepartmentGetResponse.DeptGetResponse deptGetResponse,Company company){
        company.setErpParentId(deptGetResponse.getParentId().toString());
        String idPath = "";
        if(StringUtils.isNotBlank(company.getErpParentId()) && !StringUtils.equals(company.getErpParentId(),Constants.ONE+"")){
            Company parent = companyMapper.selectOne(new QueryWrapper<Company>().lambda().eq(Company::getErpId,company.getErpParentId())
                    .eq(Company::getIsdeleted,Constants.ZERO).last("limit 1 "));
            if(parent == null || Constants.equalsInteger(parent.getIsdeleted(),Constants.ONE)){
                throw new BusinessException(ResponseStatus.DATA_EXISTS.getCode(), "对不起,父级组织信息不存在~");
            }
            if(Objects.nonNull(parent.getType())&&!Constants.equalsInteger(parent.getType(),-1)){
                if(!Constants.equalsInteger(company.getType(),parent.getType())){
                    throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"对不起,组织信息错误");
                }
            }else if(Objects.isNull(parent.getType())){
                throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"对不起,组织信息错误");
            }
            idPath = parent.getCompanyPath();
            company.setHkParentId(parent.getHkId());
            company.setCompanyPath(parent.getCompanyPath()+company.getId()+"/");
            company.setCompanyNamePath(parent.getCompanyNamePath()+"/"+company.getName());
        }
        company.setName(deptGetResponse.getName());
        company.setErpId(deptGetResponse.getDeptId().toString());
        company.setErpParentId(deptGetResponse.getParentId().toString());
        company.setSortnum(deptGetResponse.getOrder().intValue());//默认最上面
        company.setEditDate(new Date());
        company.setHkCompanyPath(company.getCompanyNamePath());
        company.setHkStatus(Constants.ZERO);
        company.setStatus(Constants.ZERO);
        company.setSortnum(deptGetResponse.getOrder().intValue());
        company.setHkDate(company.getCreateDate());
        company.setEditDate(company.getCreateDate());
        company.setEditor(company.getCreator());
        company.setPinyin(Constants.getChinesePingyin(company.getName()));
        companyMapper.updateById(company);
        //下发海康安防平台
        Boolean issueStatus = editHkOrg(company);
        Company com = new Company();
        com.setId(company.getId());
        com.setHkId(issueStatus?company.getHkId():null);
        com.setHkStatus(issueStatus?Constants.ONE:Constants.TWO);
        com.setCompanyPath(idPath+company.getId()+"/");
        companyMapper.updateById(com);
        return company;
    }
    public void syncDelCompany(List<Long> deptIdList){
        List<Company> companyList = companyMapper.selectList(new QueryWrapper<Company>()
                .lambda()
                .eq(Company::getIsdeleted,Constants.ZERO)
                .in(Company::getErpId,deptIdList)
        );
        if(CollectionUtils.isNotEmpty(companyList)){
            List<Integer> delIds = companyList.stream().map(i->i.getId()).collect(Collectors.toList());
            List<String> delHKIds = companyList.stream().filter(i->StringUtils.isNotBlank(i.getHkId())).map(i->i.getHkId()).collect(Collectors.toList());
            //标记业务删除
            companyMapper.update(new UpdateWrapper<Company>().lambda()
                    .set(Company::getIsdeleted,Constants.ONE)
                    .set(Company::getEditDate,new Date())
                    .in(Company::getId,delIds)
            );
            //海康删除的数据,进行删除
            doHkDeleteOrg(delIds,delHKIds,new Date());
        }
    }
}
server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/MemberServiceImpl.java
@@ -7,10 +7,13 @@
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.dingtalk.api.response.OapiV2DepartmentGetResponse;
import com.dingtalk.api.response.OapiV2UserGetResponse;
import com.doumee.biz.system.SystemDictDataBiz;
import com.doumee.config.DataSyncConfig;
import com.doumee.core.annotation.excel.ExcelImporter;
import com.doumee.core.constants.ResponseStatus;
import com.doumee.core.dingTalk.DingTalk;
import com.doumee.core.exception.BusinessException;
import com.doumee.core.haikang.model.HKConstants;
import com.doumee.core.haikang.model.param.BaseResponse;
@@ -54,6 +57,7 @@
import com.doumee.service.business.third.model.response.TmsEmployeeListResponse;
import com.doumee.service.system.SystemLoginService;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.taobao.api.ApiException;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
@@ -67,6 +71,7 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import shade.com.alibaba.fastjson2.JSONArray;
import java.math.BigDecimal;
import java.util.Date;
@@ -138,7 +143,10 @@
    private SmsEmailService smsEmailService;
    @Autowired
    private SystemLoginService systemLoginService;
    private SystemLoginService systemLoginService;
    @Autowired
    private DingTalk dingTalk;
    
    @Value("${debug_model}")
    private Boolean isDebug;
@@ -211,9 +219,9 @@
    private Member initAddMemberModel(Member member, LoginUserInfo loginUserInfo) {
        Member insert=  new Member();
        insert.setCreator(loginUserInfo.getId());
        insert.setCreator(Objects.nonNull(loginUserInfo.getId())?loginUserInfo.getId():null);
        insert.setCreateDate(new Date());
        insert.setEditor(loginUserInfo.getId());
        insert.setEditor(Objects.nonNull(loginUserInfo.getId())?loginUserInfo.getId():null);
        insert.setEditDate(new Date());
        insert.setHkOrgId(member.getHkOrgId());
        insert.setIsdeleted(Constants.ZERO);
@@ -400,6 +408,10 @@
            }
        }
    }
    private Member isMemberUpdateParamValid(Member member) {
        Member model = memberJoinMapper.selectJoinOne(Member.class,new MPJLambdaWrapper<Member>()
                .selectAll(Member.class)
@@ -980,14 +992,14 @@
            }
            TrainTime trainTime = new TrainTime();
            trainTime.setIsdeleted(Constants.ZERO);
            trainTime.setCreator(loginUserInfo.getId());
            trainTime.setCreator(Objects.nonNull(loginUserInfo)?loginUserInfo.getId():null);
            trainTime.setCreateDate(new Date());
            trainTime.setEdirot(trainTime.getCreator());
            trainTime.setEditDate(trainTime.getCreateDate());
            trainTime.setStartTime(updateMember.getTrainStartTime());
            trainTime.setEndTime(updateMember.getTrainEndTime());
            trainTime.setMemberId(updateMember.getId());
            trainTime.setImportInfo("由【"+loginUserInfo.getRealname()+"】于"+DateUtil.getPlusTime2(trainTime.getCreateDate())+(i==0?"创建":"更新")+"录入");
            trainTime.setImportInfo("由【"+(Objects.nonNull(loginUserInfo)?loginUserInfo.getRealname():"钉钉同步")+"】于"+DateUtil.getPlusTime2(trainTime.getCreateDate())+(i==0?"创建":"更新")+"录入");
            //导入培训有效期
            trainTimeMapper.insert(trainTime);
        }
@@ -2330,5 +2342,231 @@
    }
    /**
     * åŒæ­¥é’‰é’‰å†…部员工信息
     */
    public void syncDDUserInfo() throws ApiException {
        List<OapiV2UserGetResponse.UserGetResponse>  list = dingTalk.syncAllUserInfo();
        if(CollectionUtils.isEmpty(list)){
            return;
        }
        List<Member> addList = new ArrayList<>();
        List<Member> updateList = new ArrayList<>();
        List<String> delIds = new ArrayList<>();//修改为使用钉钉id  erpId
        List<Member>  allList = memberMapper.selectList(new QueryWrapper<Member>().lambda()
                .eq(Member::getIsdeleted,Constants.ZERO)
                .eq(Member::getType,Constants.TWO));
        dealMemberChangeList(list,addList,updateList,delIds,allList);
        if(delIds.size()>0){
            syncDelMember(delIds);
        }
    }
    private void syncDelMember(List<String> delIds) {
        List<Member> memberList = memberMapper.selectList(new QueryWrapper<Member>().lambda().in(Member::getErpId,delIds)
                .eq(Member::getIsdeleted,Constants.ZERO));
        if(CollectionUtils.isNotEmpty(memberList)){
            for (Member member:memberList) {
                this.deleteById(member.getId(),null);
            }
        }
    }
    private void dealMemberChangeList(List<OapiV2UserGetResponse.UserGetResponse> list, List<Member> addList, List<Member> updateList, List<String> delIds, List<Member> allList) {
        Date date = new Date();
        for(OapiV2UserGetResponse.UserGetResponse respone : list){
            //根据erpid查询企业信息,判断是新增还是更新
            Member member = findMemberByERPId(allList,respone.getUnionid());
            if(member == null){
                //如果是新增
                //封装新增组织对象数据
                addList.add(getAddMemberModel(respone,new Member()));
            }else{
                updateList.add(getUpdateMemberModel(respone,member));
            }
        }
        if(allList!=null && allList.size()>0){
            for(Member m : allList){
                if(!isMemberDeleted(m,list)){
                    delIds.add(m.getErpId());
                }
            }
        }
    }
    private Member getAddMemberModel(OapiV2UserGetResponse.UserGetResponse deptGetResponse,Member member) {
        return  syncDDAddMemberModel(deptGetResponse,member);
    }
    private Member getUpdateMemberModel(OapiV2UserGetResponse.UserGetResponse deptGetResponse,Member member) {
        return  syncDDEditMemberModel(deptGetResponse,member);
    }
    private Member syncDDAddMemberModel(OapiV2UserGetResponse.UserGetResponse deptGetResponse,Member member) {
        member.setCreateDate(new Date());
        member.setErpId(deptGetResponse.getUserid());
        member.setPhone(deptGetResponse.getMobile());
        member.setName(deptGetResponse.getName());
        member.setCode(deptGetResponse.getJobNumber());
        isMemberParamValidDetail(member,deptGetResponse.getDeptIdList());
        //获取出生日期
        //脱敏操作
        Member insert = initAddMemberModel(member,null);
        //海康人员新增业务
        insert.setHkStatus(dealHkUserBiz(insert)?Constants.ONE:Constants.TWO);
        insert.setHkDate(new Date());
        memberMapper.insert(insert);
        //如果是内部组织人员,新增系统登陆账号
        systemUserMapper.insert(createSystemUser(insert,systemDictDataBiz));
        //处理培训有效期业务
        dealTrainTIme(member,0,null);
        return insert;
    }
    public void isMemberParamValidDetail(Member member,List<Long> deptIdList) {
        if(memberMapper.selectCount(new QueryWrapper<Member>().lambda()
                .eq(Member::getPhone,  member.getPhone())
                .in(Member::getType,new Integer[]{Constants.ZERO,Constants.TWO})
                .eq(Member::getIsdeleted,Constants.ZERO) ) >0){
            //throw new BusinessException(ResponseStatus.DATA_EXISTS.getCode(), "手机号【"+member.getPhone()+"】已被使用,不能重复");
        }
        if(Objects.nonNull(deptIdList)){
            List<Company> companyList = companyMapper.selectList(new QueryWrapper<Company>().lambda().in(Company::getErpId,deptIdList)
                    .eq(Company::getType,Constants.ONE).eq(Company::getIsdeleted,Constants.ZERO)
                    .isNotNull(Company::getHkId)
            );
            if(CollectionUtils.isNotEmpty(companyList)){
                member.setHkOrgId(companyList.get(Constants.ZERO).getHkId());
                member.setCompanyId(companyList.get(Constants.ZERO).getId());
            }
        }
        member.setCompanyType(Constants.ONE);
        SystemUser queryUserDto = new SystemUser();
        queryUserDto.setUsername(member.getPhone());
        queryUserDto.setDeleted(Boolean.FALSE);
        SystemUser user = systemUserMapper.selectOne(new QueryWrapper<>(queryUserDto).last("limit 1"));
        if (user != null) {
            throw new BusinessException(ResponseStatus.DATA_EXISTS.getCode(), "手机号【"+queryUserDto.getUsername()+"】已被使用,不能重复");
        }
//        // éªŒè¯å·¥å·
        if (StringUtils.isNotBlank(member.getCode())) {
            queryUserDto = new SystemUser();
            queryUserDto.setDeleted(Boolean.FALSE);
            queryUserDto.setEmpNo(member.getCode());
            user = systemUserMapper.selectOne(new QueryWrapper<>(queryUserDto).last("limit 1"));
            if (user != null) {
                throw new BusinessException(ResponseStatus.DATA_EXISTS.getCode(), "工号【"+member.getCode()+"】已存在");
            }
        }
    }
    public Member syncDDEditMemberModel(OapiV2UserGetResponse.UserGetResponse deptGetResponse,Member updateMember) {
        updateMember.setEditDate(new Date());
        updateMember.setErpId(deptGetResponse.getUserid());
        updateMember.setPhone(deptGetResponse.getMobile());
        updateMember.setName(deptGetResponse.getName());
        updateMember.setCode(deptGetResponse.getJobNumber());
        updateMember.setHkId(null);
        updateMember.setAuthStatus(Constants.ZERO);
        Boolean hkFlag = dealHkUserForUpdateBiz(updateMember);
        memberMapper.update(null,new UpdateWrapper<Member>().lambda()
                .set(Member::getStartTime,null)
                .set(Member::getEndTime,null)
                .set(Member::getRoleId,null)
                .set(Member::getHkStatus,hkFlag?Constants.ONE:Constants.TWO)
                .set(StringUtils.isNotBlank(updateMember.getPhone()),Member::getPhone,updateMember.getPhone())
                .set(StringUtils.isNotBlank(updateMember.getName()),Member::getName,updateMember.getName())
                .set(Member::getEditDate,updateMember.getEditDate())
                .set(Member::getEditor,updateMember.getEditor())
                .set(StringUtils.isNotBlank(updateMember.getName()),Member::getPinyin,Constants.getChinesePingyin(updateMember.getName()))
                .set(StringUtils.isNotBlank(updateMember.getIdcardNo()),Member::getIdcardNo,updateMember.getIdcardNo())
                .set(StringUtils.isNotBlank(updateMember.getIdcardDecode()),Member::getIdcardDecode,updateMember.getIdcardDecode())
                .set( Member::getAuthStatus,Constants.ZERO)
                .set(updateMember.getSex()!=null,Member::getSex,updateMember.getSex())
                .set(updateMember.getFaceStatus()!=null,Member::getFaceStatus,updateMember.getFaceStatus())
                .set(updateMember.getHkDate()!=null,Member::getHkDate,updateMember.getHkDate())
                .set(StringUtils.isNotBlank(updateMember.getRemark()),Member::getRemark,updateMember.getRemark())
                .set(StringUtils.isNotBlank(updateMember.getFaceImg()),Member::getFaceImg,updateMember.getFaceImg())
                .set(updateMember.getFaceId()!=null,Member::getFaceId,updateMember.getFaceId())
                .set(updateMember.getCompanyId()!=null,Member::getCompanyId,updateMember.getCompanyId())
                .set(Member::getCode,updateMember.getCode())
                .set( updateMember.getPositionId()!=null,Member::getPositionId,updateMember.getPositionId())
                .set( updateMember.getIsDangyuan()!=null,Member::getIsDangyuan,updateMember.getIsDangyuan())
                .set( updateMember.getJobDate()!=null,Member::getJobDate,updateMember.getJobDate())
                .eq(Member::getId,updateMember.getId()));
        dealTrainTIme(updateMember,1,null);
        cancelAllMemberEmpower(updateMember,memberRoleMapper,empowerMapper);
        //记录操作日志
        saveUserActionBiz(updateMember,null,Constants.UserActionType.EDIT,userActionJoinMapper,null);
        return updateMember;
    }
    /**
     * æ ¹æ®ERPID  åˆ¤æ–­æ•°æ®æ˜¯å¦å·²åœ¨é›†åˆé‡Œå­˜åœ¨
     * @param allList
     * @param id
     * @return
     */
    private Member findMemberByERPId(List<Member> allList, String id) {
        if(allList!=null){
            for(Member com :allList){
                if(StringUtils.equals(com.getErpId(),id)){
                    return com;
                }
            }
        }
        return  null;
    }
    private boolean isMemberDeleted(Member member, List<OapiV2UserGetResponse.UserGetResponse> list) {
        for(OapiV2UserGetResponse.UserGetResponse m : list){
            if(StringUtils.equals(m.getUnionid(),member.getErpId())){
                return  true;
            }
        }
        return false;
    }
    public void ddPushMemberInfo(String eventType, shade.com.alibaba.fastjson2.JSONObject eventData) throws ApiException {
        JSONArray jsonArray = eventData.getJSONArray("userId");
        if(jsonArray.isEmpty()){
            return;
        }
        if(eventType.equals("user_leave_org")){
            //删除对人员信息
            List<String> userIdList = new ArrayList<>();
            for (int i = 0; i < jsonArray.size(); i++) {
                String deptId = jsonArray.getString(i);
                userIdList.add(deptId);
            }
            if(CollectionUtils.isNotEmpty(userIdList)){
                syncDelMember(userIdList);
            }
        }else if(eventType.equals("user_add_org")||eventType.equals("user_modify_org")){
            for (int i = 0; i < jsonArray.size(); i++) {
                Member member  = memberMapper.selectOne(new QueryWrapper<Member>().lambda()
                        .eq(Member::getIsdeleted,Constants.ZERO)
                        .eq(Member::getErpId,jsonArray.getLong(i))
                        .last(" limit 1")
                );
                OapiV2UserGetResponse.UserGetResponse deptGetResponse = dingTalk.syncUserInfo(jsonArray.getString(i));
                if(Objects.isNull(member)){
                    getAddMemberModel(deptGetResponse,member);
                }else{
                    getUpdateMemberModel(deptGetResponse,member);
                }
            }
        }
    }
}