前言:【【非原创】】UiPath Advanced RPA Developer Certification Training的课程资料机翻版。
课程链接:Link
欢迎!
**Orchestrator 是 UiPath 平台的核心,为自动化和机器人提供管理功能。**这可以应用于小型部署以及企业规模,其中组织建模也是必要的。
我们在这里从 RPA 开发人员的角度介绍 Orchestrator。我们将更多地坚持在开发中使用 Orchestrator 功能以及它们在运行时的工作方式,而不是在管理方面。除此之外,我们还将研究使用 Orchestrator 作为库、资产( assets)等存储库的可能性。
您将在本课程中学到什么
在本课程结束时,您应该能够:
定义 Orchestrator 的用途和主要功能。
描述 Orchestrator 实体及其用途,并区分 tenant context和 folder context。
从 Orchestrator 创建、配置和供应无人值守机器人。
使用无人值守机器人以不同方式执行作业 :作为单独作业、队列或大规模部署。
描述如何在 Orchestrator 中分配和使用许可证。
建立大规模无人值守的机器人劳动力。
直接在 Studio 中使用 Orchestrators 资源。
在 Orchestrator 中发布、安装和更新库和模板。
将文件存储在storage buckets中并在自动化项目中使用它们。
使用触发器和 SLAs 自动执行作业。
我需要什么技术设置?
UiPath Orchestrator 的演示实例
如果您工作的公司有用于开发或测试的 Orchestrator 实例,请请求访问。您将需要一个 Studio 许可证和一个无人值守许可证。
如果您无法确保这一点,UiPath 自动化云的社区计划始终是一个选项。它为您提供所需的一切,包括 Orchestrator、有人值守许可证和无人值守许可证。立即访问以下链接创建您的帐户。
UiPath Studio 安装在您的机器上并连接到 Orchestrator
您将需要它来跟进项目的开发,以及利用 Studio 和 Orchestrator 之间的协同作用。
如果您不知道该怎么做,请返回学院并查找 RPA 开发入门课程。
一个单独的工作站来安装您的无人值守机器人
只要连接到互联网,一台简单的 Windows 机器就可以做到。更好的是,Windows 服务器计算机或虚拟机将允许您在更大范围内尝试无人值守自动化。
Orchestrator 是 UiPath 平台的组件,用于管理自动化、机器人和相关实体。尽管有不同的云和本地部署选项以及由节点、服务器和高可用性功能组成的相当复杂的基础设施,但用户可以通过简单的 Web 界面访问它。
Orchestrator 提供基于角色的访问控制以及租户和文件夹结构来复制组织结构。用户可以使用无人值守的机器人劳动力运行在 Studio 中开发并发布到 Orchestrator 的自动化工作流。此外,Orchestrator 用于管理和分发许可证,以及存储自动化资源。
Provisioning:创建并维护与机器人和参与用户的连接。
控制和许可证分发:启用许可证、角色、权限、组和文件夹层次结构的创建、分配和维护。
以无人参与模式运行自动化作业:支持以各种方式创建和分发自动化作业,包括通过队列和触发器。
自动化存储和分发:允许对自动化项目、资产和凭证以及自动化中使用的大型文件进行受控存储和分发。
Monitoring:允许监控作业和机器人并存储日志以进行审计和分析。
Inter-connectivity:充当第三方解决方案或应用程序的集中通信点。
我们先来看看 UiPath 平台的核心 RPA 组件是如何协同工作的。让我们熟悉所涉及的实体。
现在让我们快速回顾一下这些实体:
就像文件夹一样,tenants旨在在 Orchestrator 的同一实例中复制组织层次结构。
从层次结构的角度来看,文件夹是tenants的细分。虽然在文件夹的情况下更多的是关于层次结构和分离,但tenants之间显然是相互隔离的。
考虑一家典型的大公司,其中数据和业务流程通常在销售和财务等部门之间分开。但是,这些细分部门会将一些数据或一些流程分开,同时共享其他数据。
在 Orchestrator 中,一些实体存在于tenants context中,而其他实体存在于 folder context中:
从上面定义的实体来看,Robot是租户实体。这意味着它们可以分配到该租户中的多个文件夹。使用角色和权限,可以自定义机器人处理每个文件夹的方式。我们稍后会看到。
使用提要( feeds)将包发布到 Orchestrator。订阅源可以配置为租户级别或文件夹级别。然后可以在任何文件夹中的流程中使用发布到租户源的包。如果它是使用文件夹源发布的,则不能用于其他文件夹中的进程。
还有一些其他 Orchestrator 实体存在于租户级别:
From the entities defined at the beginning of the lesson, processes and jobs are folder entities.Packages depend on the feed configuration.
除此之外,文件夹级别还存在其他几个实体:
Asset
An asset 是存储在 Orchestrator 中供机器人使用的一段数据。有四种类型的资产:
资产可以具有全局价值或每个用户的价值。这意味着只有指定用户才能访问存储在该资产中的特定值。
Storage bucket
Storage buckets是用于存储可用于自动化项目的文件的实体。
Queue
队列是可以容纳无限数量项目、存储不同类型数据的容器。
将物品送入队列的过程通常与处理队列物品的过程不同,由不同的机器人处理。
Trigger
触发器能够以结构化的方式执行作业。有两种类型的触发器:
角色是一组权限,用于控制人类用户和机器人对租户和文件夹实体的访问。
每个权限都由至少一个操作类型(查看、编辑、创建和删除)和一个实体(无论是租户级别还是文件夹级别)的组合定义。例如,您可以设置权限只查看某个文件夹中的队列,而不能查看其他队列,并且不做任何其他操作。
以下是可以设置个人权限的实体:
Tenant entities | Folder entities |
---|---|
Alerts | Assets |
Audit | Storage Files |
Background tasks | Storage Buckets |
Libraries | Environments |
License | Execution Media |
Robots | Folder Packages |
Machines | Jobs |
ML Logs | Logs |
Packages | Monitoring |
Roles | Processes |
Settings | Queues |
Folders | Triggers |
Users | Triggers |
Webhooks | Subfolders |
Action Assignment | |
Action Catalogs | |
Actions | |
Tasks Assignment | |
Test Case Execution Artifacts | |
Test Data Queue Items | |
Test Data Queues | |
Test Set Executions | |
Test Sets | |
Test Set Schedules | |
Transactions |
默认情况下,可以在Tenant 级别创建某些角色。这些涵盖了使用文件夹的人类用户和机器人的基本需求。
Role | Level | Use |
---|---|---|
Tenant Administrator | Tenant | 具有此角色的用户可以管理租户中的所有实体,包括文件夹。 |
Allow to be Folder Administrator | Tenant | 此角色在租户级别具有最低权限,但允许拥有它的用户在文件夹级别获得管理权限。这是通过下面的Folder Administrator角色完成的。 |
Folder Administrator | Folder | 具有此角色的用户可以管理文件夹中的所有实体。此角色需要与Allow to be Folder Administrator角色一起使用。 |
Allow to be Automation User | Tenant | 此角色在租户级别具有最低权限,并允许用户获得执行存储在文件夹中的进程的权限。这是通过下面的Automation User角色完成的。参与用户和机器人都需要这个角色。 |
Automation User | Folder | 具有此角色的用户可以在文件夹中执行进程。此角色需要与租户级别的Allow to be Automation User角色结合使用。参与用户和机器人都需要这个角色。 |
让我们回顾一下!
在 Orchestrator 中,具有有人值守许可证(Robot 或 Studio)的人类用户和无人值守机器人都需要有相应的 Orchestrator 用户。
根据部署类型和组织设置,以不同方式添加和管理用户:
为了简化有人值守和无人值守机器人的创建以及许可证配置,可以在用户级别、有人值守和无人值守机器人以及有人值守机器人的组级别启用自动化机器人创建。
机器人在物理或虚拟工作站上运行。这些在 Orchestrator 中由称为机器(machines)的实体进行镜像。 Orchestrator 中的机器用作 API 密钥生成器,授权机器人和 Orchestrator 之间的连接。
Orchestrator 中有两种类型的机器:
- Machine templates:这允许使用单个 API 密钥连接到多个工作站。
- Standard machines:这允许 Orchestrator 和单个机器之间的连接。这适用于机器人需要在特定机器上运行的场景。
在 Orchestrator 中,许可证也称为runtimes。它们在机器模板级别分配,位于租户菜单中的机器下。
在那里分配的运行时数应与可以在使用该机器模板连接的单台机器上运行的最大用户数相匹配。在普通的 Windows 机器上,只有一个用户可以运行。但是在 Windows 服务器机器上,多个用户可以同时运行。
无论机器上运行的用户数量有多少,只要机器连接到 Orchestrator,就会消耗许可证。
在功能上**,有人值守自动化的目的**是让机器人准备好在人类用户需要时、在他们的工作周期和工作时间内接管不需要的任务。
当谈到无人值守自动化时,目的就大不相同:机器人需要尽可能地忙碌,尽可能少地人工输入。在下面的视频中,我们将首先再次看到无人值守机器人的配置是多么容易。然后我们将创建和运行作业,充分利用许可证消耗模型,基于 UI 交互的进程分离和作业优先级。
Video transcript
您好,欢迎观看有关 Orchestrator 文件夹无人值守自动化的演示。
在今天的视频中,我们将首先了解如何在 Orchestrator 文件夹中设置无人值守机器人。然后我们将使用我们正在设置的无人值守机器人运行后台和前台作业。在做这一切的同时,我们还将介绍工作优先级的概念。
在我们开始之前先介绍一下后台和前台进程。
后台进程,也称为 Headless Process,是指在不与任何类型的 UI 交互的情况下运行的作业。在 UiPath Studio 中构建时,需要设置一个进程在后台启动。
多个后台进程可以同时进行。
前台进程使用图形用户界面。例如,基于这种区别,前台进程可以与有人值守自动化中的一个或多个后台进程并行运行。我们现在将看到它在涉及 Orchestrator 文件夹的无人值守自动化场景中是如何工作的。
多个前台进程会依次进行。由于作业需要 UI 交互,因此作业将以顺序模式运行。第一个结束后,第二个开始。
一旦 UI 相关作业结束并且运行时被释放,无头进程的最后一个作业就会开始。发生这种情况是因为它具有比 UI 依赖进程的剩余优先级更高的优先级。
无人值守的机器人并不作为独立的实体存在。它们是 Orchestrator 中的用户和机器之间的组合,通过机器模板连接到 Orchestrator。
让我们简要回顾一下我们所做的:我们首先设置了一个机器模板和一个 Active Directory 用户,我们将它们添加到一个文件夹并运行了 10 个作业——5 个使用无头进程,另外 5 个使用前台进程。我们还为无头工作设置了高优先级。
是什么让unattended automation with folders真正有效?
The use of folders and job priorities(作业优先级)
通过在文件夹、角色和权限的帮助下准确反映业务层次结构,我们可以控制对自动化流程的访问,并确保将精力花在带来最大回报的地方。作业优先级可以确保业务优先级在自动化过程中得到很好的体现。
基于 UI 交互的进程分离
Orchestrator 中的进程现在区分为与用户界面交互的进程(称为前台进程)和不与用户界面交互的进程,称为background or headless processes。
这对自动化作业的执行方式有重大影响。无人值守的机器人可以同时运行前台作业和与机器上可用运行时一样多的无头作业。
每台机器的许可证分配
为每台机器分配许可证(运行时)可确保优化它们的使用。例如,在 Windows Server 机器上,多个机器人可以打开会话并运行无人参与的作业,最多运行时数达到最大值。
Orchestrator 中设计了无人值守自动化,以确保资源优化和有效性。但在某些情况下,业务逻辑更为重要。 Orchestrator 提供了一些功能和选项来允许自定义作业分配过程,以便某些作业或资源仅对某些用户可用:
Assets per user 每个用户的资产
可以创建和设置资产,以便只有给定的用户才能访问它们。
每个用户或机器的作业分配
当一个无人值守的工作被创建时,它可以被动态分配,任何空闲的机器人都可以捡起它。或者它可以配置为仅由特定用户拾取或在特定机器上执行。
每个用户的触发器分配
触发器可以设置为动态分配作业,或仅将作业分配给特定用户。
Orchestrator 和 Studio 之间的深度集成,通过交互式登录功能,允许 RPA 开发人员直接使用文件夹实体,如队列、资产和流程。观看下面的演示,了解如何使用 Studio 中的专用面板来加快开发速度。
好的,我们到了本演示的结尾,在演示中,我们看到了如何通过简单的拖放操作在自动化工作流中使用 Orchestrator 资源(例如资产和队列),这要归功于 Studio 和 Orchestrator 之间的深度集成。
在自动化和机器人管理的许多其他功能中,Orchestrator 还可用于存储库和模板以增加可重用性。这样,公司中的所有开发人员都可以使用 Orchestrator 作为共享开发资产并确保使用正确版本的一种方式。
演示:使用 Orchestrator 发布和安装库
存储桶是用于存储可用于自动化项目的文件的 Orchestrator 实体。 UiPath Studio 提供了一组活动来简化存储桶的使用。这些活动位于 Orchestrator 下的 UiPath.System.Activities 包中。
可以使用 Orchestrator 数据库或某些外部提供商(例如 Azure、Amazon 或 MinIO)创建存储桶。每个存储桶都是一个文件夹范围的实体,允许对存储和内容访问进行细粒度控制。
UiPath Studio 提供了许多选项来处理自动化项目中的文件。在某些情况下,存储桶可能是最好的方式:例如,当使用存储在集中位置的大文件时,或者当您需要以受控方式授予多个机器人访问权限时。
什么是Queues?
Queues是可以容纳无限数量项目的容器。项目可以存储多种类型的数据,默认情况下以自由形式存储。如果需要特定的数据模式,可以在创建队列时以 JSON 文件的形式上传。
Orchestrator 中的队列将存储项目并将它们单独分配给机器人进行处理,并根据流程结果监控项目的状态。一旦队列项目进入处理,它们就成为事务。项目是不可分割的工作单元:客户合同、发票、投诉等。
为什么需要Queues?
**在复杂逻辑强调的大规模自动化场景中,使用队列非常有用。**此类场景带来了许多挑战——将来自多个来源的项目组合在一起,根据独特的逻辑处理它们,有效利用资源,或在单个项目和队列级别报告功能,包括使用 SLA。
考虑零售公司通过表格进行的客户登记流程:客户可能来自不同的来源(在线、合作伙伴、自己的商店、呼叫中心),因此将他们添加到处理线的过程顺利至关重要。此外,使用队列将确保在 SLA 时间限制内处理这些队列。
演示:配置、填充和使用队列
在下一个视频中,我们将首先在 Orchestrator 中创建一个队列。然后我们将转到 Studio,在那里我们将创建一个调度程序来填充队列,并创建一个表演者从队列中获取数据并将其输入到网站上。
队列对于大型自动化项目极其重要。它们允许存储和处理基本上无限量的数据,前提是数据可以在事务中进行组织。队列通过容纳不同的数据类型提供了很大的灵活性。它们非常适合从不同渠道获取数据、标准化并用作其他应用程序(如 ERP 或 CRM)的输入的情况。
创建队列
在 Orchestrator 中,可以通过菜单中的同名条目轻松创建队列。它们是文件夹实体,允许设置细粒度的权限。
创建队列时,您可以设置最大重试次数(您希望队列项目重试的次数)和唯一引用字段(如果您希望事务引用唯一,请选择是)。一旦创建了队列,就无法修改这些设置。
队列创建为空,但 UiPath Studio 中有特定活动可以让机器人填充队列。 Orchestrator 也直接支持从 .csv 文件批量上传。
填充和消耗队列
为了确保机器人的最佳使用,队列通常与运行自动化的 Dispatcher-Performer 模型一起使用。在这个模型中,涉及队列的过程的两个主要阶段是分开的:
使用位于 Orchestrator 下 UiPath.System.Activities 包中的特定活动来处理队列和队列项目。这些是:
队列项目状态
队列项可以具有以下状态之一。这些将根据人类用户和机器人操作和/或使用设置交易状态活动自动设置。可以使用 Set Transaction Progress 活动为“进行中”的队列项目设置自定义子状态。
除了以上这些,已经被放弃或失败的队列项目可以进入修订阶段。在这种情况下,审阅者会设置特定的修订状态。查看下图,其中说明了两种类型的状态。
在队列课程中,我们已经看到了最复杂的事务处理模型。但不是唯一的。如果这不是您的第一门涵盖 UiPath Studio 功能的课程,那么您已经看过其他两个模型。
如果这是您的第一门涵盖 UiPath Studio 的课程,请不要担心!您将轻松掌握其他两种事务处理模型。
但首先,让我们确保我们知道什么是Transaction。
通过完成业务流程的一部分,**Transaction表示最小(原子)数据量和处理数据所需的必要步骤。**一个典型的例子是从邮箱中读取一封电子邮件并从中提取数据的过程。
我们将数据称为原子数据,因为一旦它被处理,我们就假设随着业务流程的推进,我们不再需要它。
在考虑业务流程的步骤及其重复方式时,我们可以将业务流程分为三类:
这种过程可以用一个简单的循环来实现,但它的缺点是,如果在处理一个项目时出现问题,整个过程就会中断,其他项目仍然没有处理。
3.事务性 Transactional
与迭代过程类似,事务过程的步骤在不同的数据项上重复多次。然而,自动化的设计使得每个可重复的部分都是独立处理的。
这些可重复的部分被称为事务。事务彼此独立,因为它们不共享任何数据或有任何要处理的特定顺序。
这三类流程可以看作是自动化项目的成熟阶段,从简单的线性任务开始,然后重复多次,最后演变为事务方法。
但是,这并不是对所有情况的绝对规则,应根据过程的特点(例如,正在处理的数据和重复频率)和其他相关要求(例如,易用性和稳健性)来选择类别。
我将在哪些业务场景中使用事务处理?
什么是触发器?
触发器能够以结构化的方式执行作业。有两种类型的触发器:
为什么需要触发器?
时间触发器是自动执行需要特定节奏的流程的好方法。例如,运行一个处理员工提交的费用的流程。
队列触发器可能是处理以变化且无法预测的速度填充新项目的队列的最佳选择。它们还可以证明对于具有严格 SLA 和违反它们的重大后果的流程很有价值。示例可能包括涉及客户的所有业务流程:入职、购买、投诉。
Orchestrator 中的 SLA 是什么?
Orchestrator 中的 SLA 只是 SLA 通用概念的应用。换句话说,它是提供者和客户之间的承诺,具有关于所提供服务的可衡量指标。
在 Orchestrator 中,这采用必须处理队列项目的时间间隔(以天和/或小时表示)的形式。风险 SLA 是 Orchestrator 中的后续概念,旨在确定需要采取纠正措施以避免违反 SLA 的点。
为什么在 Orchestrator 中需要 SLA?
自动化流程是基于有关队列项目量的某些假设运行的。这决定了分配给特定进程和队列的机器人容量。
在某些情况下,现实与这些假设不同。在没有 SLA 的情况下,违规行为可能会被发现为时已晚,并且会带来代价高昂的后果。
在下一个视频中,我们将使用我们在上一课中创建的队列,我们正在创建一个队列触发器并为其启用 SLA。
右侧的字段非常重要。第一个是关于触发第一个作业所需的项目数量。当您不希望在队列中有特定数量的项目之前启动进程时,这很有用。
允许的挂起和运行作业的最大数量将决定触发器的速度,它必须与分配的运行时间和机器人数量相匹配。假设我们有 2 个机器人和 2 台具有无人值守许可证的机器,让我们将此示例设置为 2。
第三个字段用于指定添加到队列中以启动新作业的新项目的数量。当以非计划方式填充队列时,这非常有用。让我们将此设置为两个。请记住,此数字是在之前设置的待处理和正在运行的作业的最大数量之上计算的。
示例其工作原理如下:每 30 分钟自动检查一次未处理的项目。如果数字满足我们在触发器创建时设置的条件,则该过程将开始。
Orchestrator 提供了用于监控作业执行、机器人和机器以及队列和 SLA 的扩展功能。最重要的是,机器人可以在开发时使用 Studio 中的特定活动在运行时发出警报。
在下面的演示中查看监控功能。
Alerts是确保机器人按照参数工作的强大工具。根据角色,用户可以启用或禁用给定组件的警报。只需导航到我的个人资料并使用专用切换。
您可能已经适应了您参加的环境。 Studio 已安装并获得许可,您有一个有人值守的机器人,通过交互式登录连接到 Orchestrator,并通过 UiPath 助手进行控制。
是时候通过配置无人值守的机器人并连接到同一个 Orchestrator 来进一步完善您的环境了。您需要一台单独的机器来部署它,并需要一个具有无人值守许可证的 Orchestrator(可以是社区自动化云)。
练习 1 - 解决方案
是时候进一步推进我们之前开发的项目了。作为一般原则,我们应该致力于将静态值排除在我们的项目之外。原因很简单,更新存储在工作流之外的值比要求开发人员更新项目更容易。
请求很简单:更新下面的项目(我们在 Studio 课程中使用 Orchestrator 资源开发的项目)以从 Orchestrator 检索 ACME URL。
练习 2 - 解决方案
您的任务是自动化在柜员应用程序“UiDemo”中插入交易的过程。与交易相关的输入数据存储在 Excel 文件中。由于交易量非常大,需要多台机器人同时工作。根据解决方案架构师 (SA) 和业务分析师 (BA) 的说法,该流程需要分配给多达 5 个机器人。
广管局已确定一项经常性业务例外:
你的任务:
UiDemo 登录凭据:
Username: admin
Password: password
解决方案
在 Orchestrator 文件夹中的队列部分下,点击添加按钮。
单击名称字段并输入名称,例如“队列 1”。
确保选中“自动重试”选项,并在“最大重试次数”部分中键入 2。
创建一个新序列并为其命名 - 即 AddItems。
使用读取范围将 Excel 文件作为数据表读取。
添加 For Each Row 活动。
拖放 Add Queue Item 活动并将其放置在 For Each Row 活动中。
在“属性”面板中选择 QueueName 字段,然后键入在前面步骤中创建的队列的名称。确保将文本放在引号之间。
ItemInformation 字段是可以添加交易项目值的地方。此过程的工作方式类似于将参数传递给调用的工作流。按下按钮。显示一个 ItemInformation 窗口,使您能够创建一个参数。
单击创建参数。
将第一个参数命名为“CashIn”。
将 ArgumentType 设置为 String 并将方向设置为 In。
通过在数据表的第一列上输入信息来填写值字段 - row(“CashIn”).ToString。
对第二个字段和第三个字段执行相同的步骤 (7-10)(命名它们:OnUsCheck 和 NotOnUsCheck)。
运行工作流。
检查 Orchestrator 中的值
找到您之前创建的队列。
按更多操作按钮并选择查看交易。显示之前创建的交易项目。
按查看详细信息按钮查看您在 Studio 中输入的值。
Orchestrator 中的每个正在运行的进程都有一个与之关联的运行状态。用户可以选择停止或终止进程。 Kill 将立即停止进程,这可能会导致不必要的错误。
Stop 将通过关闭应用程序和注销以安全的方式执行此操作。但这需要在我们的工作流程中使用“应该停止”活动。它通知在控制流到达应停止活动时是否已按下 Orchestrator 中的停止按钮。这类似于电脑游戏中的保存游戏功能。让我们这样做。
转到 Performer 的 Project 面板并打开 Main 工作流程。将流程图活动拖放到此处。
创建一个名为“counter”的 Int32 类型的新变量,默认值设置为“1”。
添加带有消息“Processing Transaction number”+counter.ToString 的日志消息
从“项目”面板将 ProcessTransactions.xaml 工作流拖放到流程图内,并将其与流程图的起点连接起来。
使用 Assign 活动在每次进程运行时将计数器的值增加 1。将此活动与上一项活动联系起来。
拖放“应该停止”活动并将其与之前使用的“分配”活动连接起来。在“属性”面板和“结果”中,按 Ctrl+K 创建一个新变量以存储此活动的输出。称之为“应该停止”。检查变量面板,您会看到“shouldStop”是使用布尔类型创建的。
此外,添加一个 Flow Decision 活动并连接它。在“条件”属性的“属性”面板中,设置变量“shouldStop”,因为我们需要检查进程是否应该停止。
对 True 案例使用日志消息活动。在其中写入一条代表性消息,例如“进程已停止。 “
对于 False 情况,将 Flow Decision 与顶部的第一个 Log 消息活动连接起来。您的工作流程应如下所示:
5. 出版表演者
从 Studio 的顶部菜单中按发布。将出现一个弹出窗口,您应该会看到有关您的包裹的信息。单击发布。
转到 Orchestrator -> 租户 -> 包。在此处搜索您的项目,您应该会看到它。
转到至少连接了一个无人值守机器人的文件夹中的进程并创建一个新进程。在包名称中选择您刚刚发布的包。
导航到作业并为您的流程创建一个新作业。选择进程,然后选择机器上的机器人,然后单击开始。
为之前创建的流程添加 2 个计划以:
解决方案