钉钉小程序生态6—钉钉OA自定义审批流的创建和使用

news2024/11/16 5:23:37

文章导航

钉钉小程序生态1—区分企业内部应用、第三方企业应用、第三方个人应用
钉钉小程序生态2—区分小程序和H5微应用
钉钉小程序生态3—钉钉扫码登录PC端网站
钉钉小程序生态4—钉钉小程序三方企业应用事件与回调
钉钉小程序生态5—钉钉群机器人消息通知和钉钉工作通知
钉钉小程序生态6—钉钉OA自定义审批流的创建和使用

前言

大家好!我是sum墨,一个一线的底层码农,平时喜欢研究和思考一些技术相关的问题并整理成文,限于本人水平,如果文章和代码有表述不当之处,还请不吝赐教。

钉钉作为一款办公软件,审批功能是它的核心功能之一,最常见的审批场景就是请假和报销了。虽然钉钉也内置了一些审批流,但是审批场景层出不穷,光靠钉钉内置的那些是不够用的。尤其一些公司自己也有技术团队,则更希望可以二次开发一下,做一套更适合自己公司的审批流。那么本文我们就钉钉的审批能力来讲一下:钉钉OA自定义审批流的创建和使用。

tips:钉钉OA审批在哪里

这个还是要说下,否则很多人都找不到!

1. 扫码登录钉钉OA

登录链接如下:https://oa.dingtalk.com/

2. 工作台-应用管理-OA审批-进入

进去之后是这样的,我们也可以在这里创建新表单,不过这里创建的表单是不支持代码调用的。

3. 如果实在找不到,去搜索框中搜索审批

那么,接下来正文开始!

一、创建小程序

如果你的组织的类型是认证服务商,那么可以选择创建第三方企业应用,否则就创建企业内部应用。

这两种应用的主要区别就是获取AccessToken的方式不同,如何不同可以看我的这篇文章:钉钉小程序生态1—区分企业内部应用、第三方企业应用、第三方个人应用

那么如何判断自己是不是服务商组织呢?登录开放平台—>首页—>有认证服务商标签的就是啦

这里我为了方便文章撰写,我就创建一个企业内部应用来说明接下来的流程。如果大家使用的是第三方企业应用,那么还需要配置一下钉钉事件回调,详细可见我这篇文章:
钉钉小程序生态4—钉钉应用事件与回调

1. 应用开发-企业内部应用-创建应用-H5微应用

这里H5微应用、小程序两种类型都可以,我们主要是为了获取创建钉钉OA自定义审批流的权限。

2. 基础信息—权限管理—搜索审批

权限一共5个全都点申请,将对应权限权限申请好之后,我们就可以调用接口创建OA审批模板和发起审批实例了。

3. 应用功能—事件与回调—事件订阅—开启审批事件回调

如何接入可以看钉钉的官方文档:配置Stream推送,非常的简单,这里我就不贴代码了。
配置回调的作用是为了后续审批状态发生变化的时候可以及时通知到我们。

到目前为止,创建和配置相关的工作我们已经完成了,接下来就是开发了。

二、创建或更新审批表单模板

模板的创建是一次性的,也就是说只需要调用一下创建接口就行,这里复杂的东西是它的控件很多,比如:文本框、数字框、日期选择器等等,如下图:

用可视化界面创建固然是容易,但是要用代码来创建就有点麻烦了,我开始也错了好几次,从简单的控件开始尝试就好了,多试几次就行。
官方链接如下:创建或更新审批表单模板
这里我自己创建的代码如下:

package com.example.dingtalkoa.demo;

import com.aliyun.dingtalkworkflow_1_0.models.FormComponent;
import com.aliyun.dingtalkworkflow_1_0.models.FormComponentProps;
import com.aliyun.dingtalkworkflow_1_0.models.FormCreateHeaders;
import com.aliyun.dingtalkworkflow_1_0.models.FormCreateRequest;
import com.aliyun.dingtalkworkflow_1_0.models.FormCreateResponse;
import com.aliyun.tea.TeaException;
import com.aliyun.teaopenapi.models.Config;
import com.aliyun.teautil.Common;
import com.aliyun.teautil.models.RuntimeOptions;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class Sample3 {

    /**
     * 获取AccessToken
     *
     * @return
     */
    public static String getAccessToken() throws Exception {
        com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config();
        config.protocol = "https";
        config.regionId = "central";
        com.aliyun.dingtalkoauth2_1_0.Client client = new com.aliyun.dingtalkoauth2_1_0.Client(config);
        com.aliyun.dingtalkoauth2_1_0.models.GetAccessTokenRequest getAccessTokenRequest
            = new com.aliyun.dingtalkoauth2_1_0.models.GetAccessTokenRequest()
            .setAppKey("xxx")
            .setAppSecret("xxxx");
        try {
            return client.getAccessToken(getAccessTokenRequest).getBody().getAccessToken();
        } catch (TeaException err) {
            if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) {
                // err 中含有 code 和 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 属性,可帮助开发定位问题
            }

        }
        return null;
    }

    public static void main(String[] args) throws Exception {
        Config config = new Config();
        config.protocol = "https";
        config.regionId = "central";
        com.aliyun.dingtalkworkflow_1_0.Client client = new com.aliyun.dingtalkworkflow_1_0.Client(config);
        FormCreateHeaders formCreateHeaders = new FormCreateHeaders();
        formCreateHeaders.xAcsDingtalkAccessToken = getAccessToken();
        // 1. 单行输入控件
        FormComponentProps formComponentProps1 = new FormComponentProps()
            .setComponentId("TextField-title")
            .setPlaceholder("文章标题")
            .setLabel("文章标题")
            .setRequired(true);
        FormComponent formComponent1 = new FormComponent()
            .setComponentType("TextField")
            .setProps(formComponentProps1);
        FormComponentProps formComponentProps2 = new FormComponentProps()
            .setComponentId("TextField-url")
            .setPlaceholder("文章内容链接")
            .setLabel("文章内容链接")
            .setRequired(true);
        FormComponent formComponent2 = new FormComponent()
            .setComponentType("TextField")
            .setProps(formComponentProps2);

        FormCreateRequest formCreateRequest = new FormCreateRequest()
            .setName("文章发布申请")
            .setDescription("文章发布申请")
            .setFormComponents(java.util.Arrays.asList(formComponent1, formComponent2));
        try {
            FormCreateResponse formCreateResponse = client.formCreateWithOptions(formCreateRequest, formCreateHeaders,
                new RuntimeOptions());
            System.out.println("创建的processCode:" + formCreateResponse.getBody().getResult().getProcessCode());
        } catch (TeaException err) {
            log.error("--->", err);
            if (!Common.empty(err.code) && !Common.empty(err.message)) {
                // err 中含有 code 和 message 属性,可帮助开发定位问题
            }

        } catch (Exception _err) {
            log.error("--->", _err);
            TeaException err = new TeaException(_err.getMessage(), _err);
            if (!Common.empty(err.code) && !Common.empty(err.message)) {
                // err 中含有 code 和 message 属性,可帮助开发定位问题
            }

        }
    }

}

maven依赖代码如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.17</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>DingTalkOA</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>DingTalkOA</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>com.dingtalk.open</groupId>
            <artifactId>app-stream-client</artifactId>
            <version>1.1.0</version>
        </dependency>

        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>dingtalk</artifactId>
            <version>2.0.14</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.26</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

创建好之后可以在OA里面找到刚才创建的审批流模板

审批表单模板创建结束后,钉钉会返回一个processCode给我们,这个processCode很重要需要保存下来。整体来说,审批表单模板的创建不难理解,毕竟在这里不需要设置各个环节的审批人,真正复杂的是发起审批实例这个接口,下面我们来讲一下如何发起审批实例。

三、发起审批实例

1. 参数说明

  • processCode
    审批模板code,好理解。
  • originatorUserId
    审批发起人的userId,也理解。
  • deptId或approvers
    选择审批的部门或者审批的人,这是二选一,传一个就行了,理解上还行。
  • ccList
    抄送人 userId,就是只会通知到他,而不用他点审批的人,好理解。
  • ccPosition
    抄送时间点,取值:START:开始时抄送;FINISH:结束时抄送;START_FINISH:开始和结束时都抄送,理解上还行。
  • formComponentValues
    表单数据内容,控件列表,也就是我们创建的那些控件的具体的值,理解上还行。
  • microappAgentId
    不理解的来了,这个东西如果你是企业内部应用,你可以很快的在应用信息中找到,如下图

    但是!!!谁能告诉我第三方企业应用的agentId在哪???下面是第三方企业应用的应用信息,根本就没有!!!

    这是钉钉官方教我们查看官方应用和第三方应用的AgentId的方法

    但是!!!钉钉OA升级了了,不是,你们特么升级版本不考虑一下这个的吗???新版本没了,找不到了,打开是这个东西

    而且开放平台里面也根本没有可以直接获取AgentId的接口,最后找来找去,终于给找到一个接口:获取企业授权信息,这个接口的返回值里面有一个auth_info,里面有授权应用的agentId,唉,,,

2. 调用示例

官方文档:发起审批实例
这里我自己发起实例的代码如下:

package com.example.dingtalkoa.demo;

import java.util.ArrayList;
import java.util.List;

import com.alibaba.fastjson.JSONObject;

import com.aliyun.dingtalkworkflow_1_0.models.StartProcessInstanceRequest.StartProcessInstanceRequestApprovers;
import com.aliyun.dingtalkworkflow_1_0.models.StartProcessInstanceResponse;
import com.aliyun.tea.TeaException;
import com.aliyun.teaopenapi.models.Config;
import com.aliyun.teautil.models.RuntimeOptions;

public class Sample4 {
    /**
     * 获取AccessToken
     *
     * @return
     */
    public static String getAccessToken() throws Exception {
        com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config();
        config.protocol = "https";
        config.regionId = "central";
        com.aliyun.dingtalkoauth2_1_0.Client client = new com.aliyun.dingtalkoauth2_1_0.Client(config);
        com.aliyun.dingtalkoauth2_1_0.models.GetAccessTokenRequest getAccessTokenRequest
            = new com.aliyun.dingtalkoauth2_1_0.models.GetAccessTokenRequest()
            .setAppKey("xxx")
            .setAppSecret("xxx");
        try {
            return client.getAccessToken(getAccessTokenRequest).getBody().getAccessToken();
        } catch (TeaException err) {
            if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) {
                // err 中含有 code 和 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 属性,可帮助开发定位问题
            }

        }
        return null;
    }

    /**
     * 使用 Token 初始化账号Client
     *
     * @return Client
     * @throws Exception
     */
    public static com.aliyun.dingtalkworkflow_1_0.Client createClient() throws Exception {
        Config config = new Config();
        config.protocol = "https";
        config.regionId = "central";
        return new com.aliyun.dingtalkworkflow_1_0.Client(config);
    }

    public static void main(String[] args_) throws Exception {
        //调用钉钉审核发起接口
        com.aliyun.dingtalkworkflow_1_0.models.StartProcessInstanceRequest.StartProcessInstanceRequestFormComponentValues
            formComponentValues0
            =
            new com.aliyun.dingtalkworkflow_1_0.models.StartProcessInstanceRequest.StartProcessInstanceRequestFormComponentValues()
                .setName("TextField-title")
                .setValue("测试文章标题");

        com.aliyun.dingtalkworkflow_1_0.models.StartProcessInstanceRequest.StartProcessInstanceRequestFormComponentValues
            formComponentValues1
            =
            new com.aliyun.dingtalkworkflow_1_0.models.StartProcessInstanceRequest.StartProcessInstanceRequestFormComponentValues()
                .setName("TextField-url")
                .setValue("https://baidu.com");
        //获取审批人

        List<StartProcessInstanceRequestApprovers> approvers = new ArrayList<>();

        approvers.add(
            new com.aliyun.dingtalkworkflow_1_0.models.StartProcessInstanceRequest.StartProcessInstanceRequestApprovers()
                .setActionType("NONE")
                .setUserIds(java.util.Arrays.asList(
                    "xxx"
                )));

        com.aliyun.dingtalkworkflow_1_0.models.StartProcessInstanceRequest startProcessInstanceRequest
            = new com.aliyun.dingtalkworkflow_1_0.models.StartProcessInstanceRequest()
            //.setDeptId(1L)
            .setApprovers(approvers)
            .setMicroappAgentId(xxx)
            .setOriginatorUserId("xxx")
            .setProcessCode("xxx")
            .setFormComponentValues(java.util.Arrays.asList(
                formComponentValues0,
                formComponentValues1
            ));

        com.aliyun.dingtalkworkflow_1_0.Client client = createClient();
        com.aliyun.dingtalkworkflow_1_0.models.StartProcessInstanceHeaders startProcessInstanceHeaders
            = new com.aliyun.dingtalkworkflow_1_0.models.StartProcessInstanceHeaders();
        startProcessInstanceHeaders.xAcsDingtalkAccessToken = getAccessToken();
        JSONObject.toJSONString(startProcessInstanceRequest);
        StartProcessInstanceResponse startProcessInstanceResponse = client.startProcessInstanceWithOptions(
            startProcessInstanceRequest, startProcessInstanceHeaders,
            new RuntimeOptions());

    }
}

把参数都准备好之后,实现起来还是比较简单的,调用代码创建的审批实例,钉钉会返回一个实例ID:instanceId,这个instanceId和processCode一样也需要保存下来,发送成功后钉钉APP上就会自动出现一条OA审批啦。

四、审批实例状态监控

所谓审批实例状态监控,就是当前审批流程是被同意啦还是被拒绝了。这里有两种方案:

  1. 定时去调用获取单个审批实例详情接口,同步审批实例状态,优点是状态肯定可以同步到,缺点是实时性差;
  2. 通过事件订阅的方式获取审批实例的状态,优点是实时性高,审批状态变化服务端就可以指定,缺点是只会推送一次;

而作为一个成年人,这两个肯定是全都要啦,一个用来实时更新,一个用来做兜底。
这里查询的审批实例的接口文档链接如下:获取单个审批实例详情。
如果前面创建审批模板、发起审批实例都能跑通,那么这个接口也肯定不在话下,所以这里我就不贴代码了。

最后我把事件订阅推送的数据格式贴一下:

[
    {
        "result": "refuse",
        "processInstanceId": "xxx",
        "eventId": "xxx",
        "finishTime": 1698231807000,
        "createTime": 1698227806000,
        "processCode": "PROC-xxx",
        "businessId": "xxx",
        "title": "xxx提交的文章发布申请",
        "type": "finish",
        "staffId": "xxx",
        "taskId": "xxx"
    }
]

写在最后:其实这些东西大部分都是钉钉官方文档上面的,除了那个agentId… 但是钉钉文档的东西实在是太多,作为一个开发者,我们不可能去从头到尾看一遍的,一般都是用到了就去找。但是这样一来又会很混乱,所以我这篇文章主要是从开发者角度来梳理一下这个流程,不仅利己也能帮助其他人。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1133294.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【嵌入式开发学习】__单片机中容易造成内存泄露的几个痛点

目录 前言 一、程序运行 二、什么是内存泄露&#xff1f; 三、内存泄露的严重后果&#xff01; 四、如何定位到泄露的要点&#xff1f; 五、三大痛点 1. 访问越界 2. 栈 3. 堆 六、泄露常见的场景 1. 重新赋值 2. 首先释放父块 3. 返回值的不正确处理 七、常见的…

无监督学习-K-means

1、 什么是无监督学习 一家广告平台需要根据相似的人口学特征和购买习惯将美国人口分成不同的小组&#xff0c;以便广告客户可以通过有关联的广告接触到他们的目标客户。Airbnb 需要将自己的房屋清单分组成不同的社区&#xff0c;以便用户能更轻松地查阅这些清单。一个数据科学…

账号运营的底层逻辑---获客思维

什么是运营&#xff1f; 运营是做什么的&#xff1f; 什么是内容运营&#xff1f; 什么是活动运营&#xff1f; 一篇带你搞清楚所有的底层逻辑&#xff01;

三、W5100S/W5500+RP2040树莓派Pico<TCP Client数据回环测试>

文章目录 1. 前言2. 协议简介2.1 简述2.2 优点2.3 应用 3. WIZnet以太网芯片4. TCP Client数据回环测试4.1 程序流程图4.2 测试准备4.3 连接方式4.4 相关代码4.5 测试现象 5. 注意事项6. 相关链接 1. 前言 在当今的计算机网络环境中&#xff0c;TCP&#xff08;传输控制协议&am…

整理指定文件夹下的所有文件,以类树状图显示并生成对应超链接

最近在整理家里学习资料的时候&#xff0c;由于年代久远&#xff0c;找不到我想要找的文件&#xff0c;windows文件搜索速度感觉太慢。于是想要生成一份类似文件索引的东西来显示所有资料&#xff0c;让我可以快速的找到需要的资料路径 直接上代码 import os import datetim…

基于Java的医院远程预约管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09; 代码参考数据库参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&am…

2、Linux权限理解

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 目录 前言 Linux权限的概念 1.文件访问者的分(人) 2.文件类型和访问权限(事物属性) 3.文件权限值的表示方法 4.文件访问权限的相关设置方法 file指令 目录的权限 粘滞位 关于权限的总结 前言 在开始Linux权限理…

IDEA: 自用主题及字体搭配推荐

文章目录 1. 字体设置推荐2. 主题推荐3. Rainbow Brackets(彩虹括号)4. 设置背景图片 下面是我的 IDEA 主题和字体&#xff0c;它们的搭配效果如下&#xff1a; 1. 字体设置推荐 在使用 IntelliJ IDEA 进行编码和开发时&#xff0c;一个合适的字体设置可以提高你的工作效率和舒…

Python---for循环中的两大关键字break和continue

之前在while循环中&#xff0c;也是用到两个关键字。 相关链接&#xff1a; 所以&#xff0c;在循环结构中都存在两个关键字&#xff1a;break和continue break&#xff1a;主要功能是终止整个循环 break&#xff1a;代表终止整个循环结构 continue&#xff1a;代表中止当…

【Note】二叉树的遍历

二叉树的遍历 二叉树的基本结构&#xff1a;根节点&#xff08;Data&#xff09;、左子树&#xff08;LChild&#xff09;和右子树&#xff08;RChild&#xff09;。 因此只要依次遍历这三部分&#xff0c;就遍历了整个二叉树。 如果用L、D、R分别表示遍历左子树、访问根结点…

不用编程超简单的自动化测试工具:Airtest入门篇教程!

目录 一、背景 二、什么是Airtest 三、Airtest下载安装 四、Airtest入门使用教程 4.1 连接设备&#xff1a; 4.2 具体测试场景案例&#xff1a; 五、总结 一、背景 很多刚入行或从其他行业转行做测试的同学&#xff0c;日复一日每天做点工已经点得疲惫和麻木&#xff0…

SparkSQL执行流程与Catalyst优化器

目录 一、SparkSQL运行流程与Catalyst优化器 &#xff08;1&#xff09;RDD运行流程 &#xff08;2&#xff09;SparkSQL自动优化 &#xff08;3&#xff09;Catalyst优化器流程 &#xff08;4&#xff09;Catalyst优化器总结 &#xff08;5&#xff09;Spark SQL执行流程 一、…

Leo赠书活动-02期 【信息科技风险管理:合规管理、技术防控与数字化】

✅作者简介&#xff1a;大家好&#xff0c;我是Leo&#xff0c;热爱Java后端开发者&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;Leo的博客 &#x1f49e;当前专栏&#xff1a; 赠书活动专栏 ✨特色专栏&#xff1a;…

五、W5100S/W5500+RP2040树莓派Pico<UDP Client数据回环测试>

文章目录 1. 前言2. 协议简介2.1 简述2.2 优点2.3 应用 3. WIZnet以太网芯片4. UDP Client回环测试4.1 程序流程图4.2 测试准备4.3 连接方式4.4 相关代码4.5 测试现象 5. 注意事项6. 相关链接 1. 前言 UDP是一种无连接的网络协议&#xff0c;它提供了一种简单的、不可靠的方式来…

Premiere Pro(Pr)2023软件下载及安装教程

目录 一.简介 二.安装步骤 软件&#xff1a;Pr版本&#xff1a;2023语言&#xff1a;简体中文大小&#xff1a;8.30G安装环境&#xff1a;Win11/Win10&#xff08;1809版本以上&#xff09;硬件要求&#xff1a;CPU2.6GHz 内存8G(或更高&#xff0c;不支持7代以下CPU&#xf…

Android系统启动

首语 Android系统启动与应用启动、四大组件、AMS等很多内容都有关联&#xff0c;因此&#xff0c;Android系统启动是首先需要了解的知识。 Android 系统启动流程 Android系统流程主要部分如上图所示。下面对各个流程进行解析。 Boot ROM 启动电源以及系统启动。当电源按下时…

启动1000万个虚拟线程需要多少时间?需要多少平台线程?

之前&#xff0c;在Java新特性专栏中&#xff0c;我们简单介绍了Java 21正式发布的虚拟线程。 昨天&#xff0c;正好看到一个讲解此内容的视频&#xff0c;非常不错&#xff0c;所以DD这里给大家翻译好了&#xff0c;感兴趣的可以看看。可以进一步了解虚拟线程。 什么是虚拟线…

二进制搭建 Kubernetes+部署网络组件+部署CornDNS+负载均衡部署+部署Dashboard

二进制搭建 Kubernetes v1.20 k8s集群master01&#xff1a;20.0.0.50 kube-apiserver kube-controller-manager kube-scheduler etcd k8s集群master02&#xff1a;20.0.0.100k8s集群node01&#xff1a;20.0.0.110 kubelet kube-proxy docker etcd k8s集群node02&#xff1a;20.…

ArcGIS笔记12_ArcGIS搜索工具没法用?ArcGIS运行很慢很卡?

本文目录 前言Step 1 ArcGIS搜索工具没法用Step 2 ArcGIS运行很慢很卡 前言 这是笔者最近遇到的两个小问题&#xff0c;新换了台式机&#xff0c;安装上ArcGIS后发现搜索工具没法用&#xff0c;而且感觉还不如原来笔记本运行的流畅&#xff0c;加载图层很慢&#xff0c;编辑要…