# 案例

# 背景

本文将以企业实际业务中的“合同管理”为例,介绍如何基于Alfresco-Vue来实现。

系统的扩展配置,需要使用系统管理员身份登录。

合同管理需求点:

  1. 合同起草人基于合同模板在线创建合同,此时合同为“草稿”状态,仅创建人本人可见
  2. 在线编辑合同,并可分配权限给其他人员,进行共通编辑
  3. 合同定稿后,发起审批,自动分配权限给审批人员,此时合同为“审批中”状态
  4. 合同审批流程和审批表单可在线灵活设计
  5. 合同审批通过后,状态变更为“已审批”
  6. 在合同一览中需要直观显示“合同状态”、“合同编号”、“有效期限”

审批流程:

  1. 起草合同
  2. 发起合同审批,选择合同确认人员(单人),提交审批
  3. 合同确认人员审批通过,下一步流转到合同复核,合同复核是由合同复核组内所有人员进行审批,只要有一人审批通过即可
  4. 下一步流转到合同审核,合同审核是由合同审核组内所有人员进行审批,需要所有人都审批通过
  5. 审批过程中,只要被人驳回,均流转到合同审批的发起人员进行修改,之后再次发起审批

前期准备:

  1. 打开 系统管理 > 账号管理 页面
  2. 新增公司组织:厦门艾魅尔科技有限公司
  3. 新增组 合同复核、合同审核
  4. 新增合同起草人员:林毅(加入到公司组)
  5. 新增合同确认人员:许志宏(加入到公司组)
  6. 新增合同复核人员:杨先壮、吕竹风(加入到公司组、合同复核组)
  7. 新增合同审核人员:张伟华、蔡春辉(加入到公司组、合同审核组)

# 1、创建数据模型

说明

首先,数据模型的定义并不存在唯一解。也就是说,属性可以定义在Types中,也可以定义在Aspect中,需要根据具体情况具体分析。

关于数据模型定义的一些建议,可以参考:内容建模最佳实践

在ADF-VUE中,为了能够灵活地往文档中添加属性,需要将属性都设置在Aspect中。

# 打开 系统管理 > 数据模型 页面

# 创建新的数据模型:cusModel.xml

<?xml version="1.0" encoding="UTF-8"?>

<model name="cus:model" xmlns="http://www.alfresco.org/model/dictionary/1.0">

	<!-- Optional meta-data about the model -->
	<description>Custom Model</description>
	<author>leencloud</author>
	<version>1.0</version>

	<imports>
		<!-- Import Alfresco Dictionary Definitions -->
		<import uri="http://www.alfresco.org/model/dictionary/1.0" prefix="d"/>
		<import uri="http://www.alfresco.org/model/system/1.0" prefix="sys"/>
		<!-- Import Alfresco Content Domain Model Definitions -->
		<import uri="http://www.alfresco.org/model/content/1.0" prefix="cm"/>
	</imports>

	<!-- Introduction of new namespaces defined by this model -->
	<!-- NOTE: The following namespace custom.model should be changed to reflect your own namespace -->
	<namespaces>
		<namespace uri="http://www.alfresco.org/model/custom/1.0" prefix="cus"/>
	</namespaces>
	
	<aspects>
		<aspect name="cus:contract">
			<title>合同</title>
      <properties>
        <property name="cus:status">
          <title>合同状态</title>
          <type>d:text</type>
          <index enabled="true">
            <atomic>true</atomic>
            <stored>false</stored>
            <tokenised>false</tokenised>
          </index>
        </property>
        <property name="cus:number">
          <title>合同编号</title>
          <type>d:text</type>
          <index enabled="true">
            <atomic>true</atomic>
            <stored>false</stored>
            <tokenised>both</tokenised>
          </index>
        </property>
        <property name="cus:valid">
          <title>有效期限</title>
          <type>d:date</type>
          <index enabled="true">
            <atomic>true</atomic>
            <stored>false</stored>
            <tokenised>false</tokenised>
          </index>
        </property>
        <property name="cus:confirm">
          <title>合同确认者</title>
          <type>d:text</type>
          <index enabled="false">
          </index>
        </property>
      </properties>
		</aspect>
  </aspects>
</model>

property中的index说明

  • enabled
    • true 生成索引(可使用alfresco search搜索该属性)
    • false 不生成索引(下方的三个配置也将不生效)
  • atomic
    • true 同步生成索引
    • false 后台异步生成索引
  • stored
    • true 属性值将存储在索引中,方便在开发环境中查看准确的索引值
    • false 在生产环境中,请设为false
  • tokenised
    • true 索引前进行分词处理,索引分词结果
    • false 索引前不进行分词处理,索引这个值
    • both 索引前进行分词梳理,索引整个值和分词结果

# 点击页面右上方的“激活”按钮,激活数据模型

# 2、创建站点

# 打开 系统管理 > 站点管理 页面

# 点击 创建站点 按钮,创建一个站点用于管理合同

关于站点类型

站点类型属于预置属性,目前没有特别的业务和功能含义。

# 3、站点配置

# 设置权限

# 进入 合同管理 站点,切换到 站点成员与权限 标签页,将 公司组 设置为站点的阅览者,合同起草人员 林毅 设置为站点的编辑者,

# 设置列

# 回到 文档库 标签页,高级列表上方的 高级列设置 按钮,删除 版本、大小 列,添加 合同编号、合同状态、有效期限 列

# 4、文件夹规则

# 新建文件夹规则

# 打开 系统管理 > 数据模型 页面

创建新的规则脚本:

  • 文件名:contract_upload
  • 规则名:合同文件上传后处理

脚本内容:

if (document.typeShort == "cm:content") {
	// 切断继承,仅限上传者访问
	document.setInheritsPermissions(false);
	// 更改合同状态
	document.properties["cus:status"] = "草稿";
	document.save();
}

# 为文件夹绑定规则

# 返回 合同管理 站点,创建新文件夹 ”2023年“ 用于存储2023年的合同

# 点击文件夹右侧的操作列中的 “...” 图标,展开操作菜单,选择 规则设置

# 点击 新建规则,为文件夹绑定刚才创建的规则

# 5、设计审批表单

说明

如果根据流程状态的不同,表单的表现形式也不同,那么需要为每个流程节点设计不同的表单

一般的情况是:发起审批时表单各项目可填写,审批阶段表单各项目不可编辑

因此我们需要设计两个表单,分别对应不同情况

# 设计发起审批节点的表单

# 打开 系统管理 > 流程表单 页面,点击 创建表单

各表单项目的字段标识

  • 合同编号:cus_number(cusModel.xml中新定义属性)
  • 有效期限:cus_valid(cusModel.xml中新定义属性)
  • 申请说明:idoc_initiatdesc(既有属性)
  • 合同确认者:cus_confirm(cusModel.xml中新定义属性)
  • 待审批文件:wf_doc(默认属性)

# 设计审批中、审批完成的表单

# 回到流程表单页面,点击表单数据右侧的 复制 按钮,将刚创建的表单复制一份

# 点击编辑,将复制出的表单各项改为“禁用”

# 激活表单

回到 流程表单 页面,将两份表单的状态改为:“激活”

# 6、设计审批流程

# 打开 系统管理 > 工作流程 页面,点击 创建流程

流程设计器知识点

关于流程设计器的使用,可参考:后端开发 > Workflow

设计的流程文件内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" xmlns:activiti="http://activiti.org/bpmn" xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.activiti.org/processdef">
  <process id="contract_approve_test" name="合同审批测试" isExecutable="true">
    <extensionElements>
      <activiti:executionListener class="org.alfresco.repo.workflow.activiti.listener.ScriptExecutionListener" event="end">
        <activiti:field name="script">
          <activiti:string>var completed = execution.getVariable('wf_completed');
// 如果是取消流程,则还原文档状态为“草稿”
if (!completed) {
	authUtil.runas(function() {
		var nodes = bpm_package.childAssocs["bpm:packageContains"];
		if (nodes) {
			for (var i=0; i&lt;nodes.length; i++) {
				var node = nodes[i];
				node.properties["cus:status"] = "草稿";
				node.save();
			}
		}
	});
}</activiti:string>
        </activiti:field>
      </activiti:executionListener>
    </extensionElements>
    <startEvent id="StartEvent_1" name="开始" activiti:formKey="form_75351084311678346338531">
      <extensionElements>
        <activiti:executionListener class="org.alfresco.repo.workflow.activiti.listener.ScriptExecutionListener" event="end">
          <activiti:field name="script">
            <activiti:string>// 记录流程历史
var hisDate = utils.toISO8601(new Date()).substr(0, 19).replace("T", " ");
var hisUser = person.properties["cm:firstName"] + "(" + person.properties["cm:userName"] + ")";
var hisAct = "wfActionStart";
bpm_package.properties["idoc:wfhis"] = hisDate + "|" + hisUser + "|" + hisAct + "|";
bpm_package.save();</activiti:string>
          </activiti:field>
        </activiti:executionListener>
      </extensionElements>
      <outgoing>Flow_1hn4w3o</outgoing>
    </startEvent>
    <userTask id="Activity_0q8spra" name="合同确认" activiti:formKey="form_75351084311678346338531-1" activiti:assignee="${cus_confirm}">
      <extensionElements>
        <activiti:executionListener class="org.alfresco.repo.workflow.activiti.listener.ScriptExecutionListener" event="start">
          <activiti:field name="script">
            <activiti:string>// 将表单中的合同确认者设置到流程变量中
var cus_confirm = bpm_package.properties["cus:confirm"];
execution.setVariable('cus_confirm', cus_confirm);
// 更改审批文档
var nodes = bpm_package.childAssocs["bpm:packageContains"];
if (nodes) {
	for (var i=0; i&lt;nodes.length; i++) {
		var node = nodes[i];
		// 将文档状态更改为:审批中
		node.properties["cus:status"] = "审批中";
		node.save();
	}
}</activiti:string>
          </activiti:field>
        </activiti:executionListener>
        <activiti:taskListener class="org.alfresco.repo.workflow.activiti.tasklistener.ScriptTaskListener" event="complete">
          <activiti:field name="script">
            <activiti:string>// 将通过/否决的信息设置到流程变量,以便决定分支走向
var wf_reviewOutcome = task.getVariable('wf_reviewOutcome');
execution.setVariable('wf_reviewOutcome', wf_reviewOutcome);
// 记录流程历史
var hisDate = utils.toISO8601(new Date()).substr(0, 19).replace("T", " ");
var hisUser = person.properties["cm:firstName"] + "(" + person.properties["cm:userName"] + ")";
var hisAct = "wfAction" + wf_reviewOutcome;
var wfhis = bpm_package.properties["idoc:wfhis"];
if (!wfhis) {
	wfhis = new Array();
}
var wf_comment = task.getVariable('wf_comment');
wfhis.push(hisDate + "|" + hisUser + "|" + hisAct + "|" + wf_comment);
bpm_package.properties["idoc:wfhis"] = wfhis;
bpm_package.save();</activiti:string>
          </activiti:field>
        </activiti:taskListener>
        <activiti:taskListener class="org.alfresco.repo.workflow.activiti.tasklistener.ScriptTaskListener" event="assignment">
          <activiti:field name="script">
            <activiti:string>// 给审批者赋予权限
authUtil.runas(function() {
	var nodes = bpm_package.childAssocs["bpm:packageContains"];
	if (nodes) {
		for (var i=0; i&lt;nodes.length; i++) {
			var node = nodes[i];
			// 给审批者赋予权限
			node.setPermission("Collaborator", task.assignee);
		}
	}
});</activiti:string>
          </activiti:field>
        </activiti:taskListener>
      </extensionElements>
      <incoming>Flow_1hn4w3o</incoming>
      <incoming>Flow_0dlq2m8</incoming>
      <outgoing>Flow_02z2rrq</outgoing>
    </userTask>
    <sequenceFlow id="Flow_1hn4w3o" sourceRef="StartEvent_1" targetRef="Activity_0q8spra" />
    <userTask id="Activity_0hxiyt6" name="合同复核" activiti:formKey="form_75351084311678346338531-1" activiti:assignee="${reviewer}">
      <extensionElements>
        <activiti:executionListener class="org.alfresco.repo.workflow.activiti.listener.ScriptExecutionListener" event="start">
          <activiti:field name="script">
            <activiti:string>// 取出合同复核组中的成员
var aGroup = people.getGroup("GROUP_contract_review");
var members = people.getMembers(aGroup);
var memberNames = new java.util.ArrayList(); 
for (var i in members) { 	
	memberNames.add(members[i].properties.userName); 
} 
// 将合同复核组中的成员设置到流程变量中
execution.setVariable('review_assign', memberNames);
// 初始化合同复核节点的变量
execution.setVariable('review_complete', false);</activiti:string>
          </activiti:field>
        </activiti:executionListener>
        <activiti:taskListener class="org.alfresco.repo.workflow.activiti.tasklistener.ScriptTaskListener" event="complete">
          <activiti:field name="script">
            <activiti:string>// 只要有一人审批即可(无论通过还是否决)
execution.setVariable('review_complete', true);
// 将通过/否决的信息设置到流程变量,以便决定分支走向
var wf_reviewOutcome = task.getVariable('wf_reviewOutcome');
execution.setVariable('wf_reviewOutcome', wf_reviewOutcome);
// 记录流程历史
var hisDate = utils.toISO8601(new Date()).substr(0, 19).replace("T", " ");
var hisUser = person.properties["cm:firstName"] + "(" + person.properties["cm:userName"] + ")";
var hisAct = "wfAction" + wf_reviewOutcome;
var wfhis = bpm_package.properties["idoc:wfhis"];
if (!wfhis) {
	wfhis = new Array();
}
var wf_comment = task.getVariable('wf_comment');
wfhis.push(hisDate + "|" + hisUser + "|" + hisAct + "|" + wf_comment);
bpm_package.properties["idoc:wfhis"] = wfhis;
bpm_package.save();</activiti:string>
          </activiti:field>
        </activiti:taskListener>
        <activiti:taskListener class="org.alfresco.repo.workflow.activiti.tasklistener.ScriptTaskListener" event="assignment">
          <activiti:field name="script">
            <activiti:string>// 给审批者赋予权限
authUtil.runas(function() {
	var nodes = bpm_package.childAssocs["bpm:packageContains"];
	if (nodes) {
		for (var i=0; i&lt;nodes.length; i++) {
			var node = nodes[i];
			// 给审批者赋予权限
			node.setPermission("Collaborator", task.assignee);
		}
	}
});</activiti:string>
          </activiti:field>
        </activiti:taskListener>
      </extensionElements>
      <incoming>Flow_0cf866a</incoming>
      <outgoing>Flow_0qnbcun</outgoing>
      <multiInstanceLoopCharacteristics activiti:collection="review_assign" activiti:elementVariable="reviewer">
        <completionCondition xsi:type="tFormalExpression">${review_complete==true}</completionCondition>
      </multiInstanceLoopCharacteristics>
    </userTask>
    <userTask id="Activity_0v1fbjk" name="合同审核" activiti:formKey="form_75351084311678346338531-1" activiti:assignee="${approver}">
      <extensionElements>
        <activiti:executionListener class="org.alfresco.repo.workflow.activiti.listener.ScriptExecutionListener" event="start">
          <activiti:field name="script">
            <activiti:string>// 取出合同审核组中的成员
var aGroup = people.getGroup("GROUP_contract_approve");
var members = people.getMembers(aGroup);
var memberNames = new java.util.ArrayList(); 
for (var i in members) { 	
	memberNames.add(members[i].properties.userName); 
} 
// 将合同审核组中的成员设置到流程变量中
execution.setVariable('approve_assign', memberNames);
// 初始化合同审核节点的变量
// 是否被否决
execution.setVariable('wf_reviewOutcome', '');
// 需要处理总数
execution.setVariable('review_complete_need', members.length);
// 当前处理总数
execution.setVariable('review_complete', 0);</activiti:string>
          </activiti:field>
        </activiti:executionListener>
        <activiti:taskListener class="org.alfresco.repo.workflow.activiti.tasklistener.ScriptTaskListener" event="complete">
          <activiti:field name="script">
            <activiti:string>// 将通过/否决的信息设置到流程变量,以便决定分支走向
var wf_reviewOutcome = task.getVariable('wf_reviewOutcome');
execution.setVariable('wf_reviewOutcome', wf_reviewOutcome);
// 记录流程历史
var hisDate = utils.toISO8601(new Date()).substr(0, 19).replace("T", " ");
var hisUser = person.properties["cm:firstName"] + "(" + person.properties["cm:userName"] + ")";
var hisAct = "wfAction" + wf_reviewOutcome;
var wfhis = bpm_package.properties["idoc:wfhis"];
if (!wfhis) {
	wfhis = new Array();
}
var wf_comment = task.getVariable('wf_comment');
wfhis.push(hisDate + "|" + hisUser + "|" + hisAct + "|" + wf_comment);
bpm_package.properties["idoc:wfhis"] = wfhis;
bpm_package.save();</activiti:string>
          </activiti:field>
        </activiti:taskListener>
        <activiti:taskListener class="org.alfresco.repo.workflow.activiti.tasklistener.ScriptTaskListener" event="assignment">
          <activiti:field name="script">
            <activiti:string>// 给审批者赋予权限
authUtil.runas(function() {
	var nodes = bpm_package.childAssocs["bpm:packageContains"];
	if (nodes) {
		for (var i=0; i&lt;nodes.length; i++) {
			var node = nodes[i];
			// 给审批者赋予权限
			node.setPermission("Collaborator", task.assignee);
		}
	}
});</activiti:string>
          </activiti:field>
        </activiti:taskListener>
      </extensionElements>
      <incoming>Flow_0am3486</incoming>
      <outgoing>Flow_09v32lj</outgoing>
      <multiInstanceLoopCharacteristics activiti:collection="approve_assign" activiti:elementVariable="approver">
        <completionCondition xsi:type="tFormalExpression">${wf_reviewOutcome=="Reject"|| review_complete &gt;= review_complete_need}</completionCondition>
      </multiInstanceLoopCharacteristics>
    </userTask>
    <endEvent id="Event_1hgiorz" name="结束">
      <extensionElements>
        <activiti:executionListener class="org.alfresco.repo.workflow.activiti.listener.ScriptExecutionListener" event="end">
          <activiti:field name="script">
            <activiti:string>// 将文档状态更改为:已审批
var nodes = bpm_package.childAssocs["bpm:packageContains"];
if (nodes) {
	for (var i=0; i&lt;nodes.length; i++) {
		var node = nodes[i];
		node.properties["cus:status"] = "已审批";
		node.properties["cus:number"] = bpm_package.properties["cus:number"];
		node.properties["cus:valid"] = bpm_package.properties["cus:valid"];
		node.save();
	}
}
// 流程标识为已完成(流程的end监听里根据这个变量判断是已完成还是流程取消)
execution.setVariable('wf_completed', true);</activiti:string>
          </activiti:field>
        </activiti:executionListener>
      </extensionElements>
      <incoming>Flow_0ow0dx1</incoming>
    </endEvent>
    <userTask id="Activity_1sb5w1v" name="申请者修改" activiti:formKey="form_75351084311678346338531" activiti:assignee="${initiator.properties.userName}">
      <extensionElements>
        <activiti:taskListener class="org.alfresco.repo.workflow.activiti.tasklistener.ScriptTaskListener" event="complete">
          <activiti:field name="script">
            <activiti:string>// 记录流程历史
var hisDate = utils.toISO8601(new Date()).substr(0, 19).replace("T", " ");
var hisUser = person.properties["cm:firstName"] + "(" + person.properties["cm:userName"] + ")";
var hisAct = "wfActionResubmit";
var wfhis = bpm_package.properties["idoc:wfhis"];
if (!wfhis) {
	wfhis = new Array();
}
wfhis.push(hisDate + "|" + hisUser + "|" + hisAct + "|");
bpm_package.properties["idoc:wfhis"] = wfhis;
bpm_package.save();</activiti:string>
          </activiti:field>
        </activiti:taskListener>
      </extensionElements>
      <incoming>Flow_0v04kgi</incoming>
      <incoming>Flow_0x8aqhn</incoming>
      <incoming>Flow_16jqt75</incoming>
      <outgoing>Flow_0dlq2m8</outgoing>
    </userTask>
    <exclusiveGateway id="Gateway_0yuqj8r" default="Flow_0cf866a">
      <incoming>Flow_02z2rrq</incoming>
      <outgoing>Flow_0v04kgi</outgoing>
      <outgoing>Flow_0cf866a</outgoing>
    </exclusiveGateway>
    <sequenceFlow id="Flow_02z2rrq" sourceRef="Activity_0q8spra" targetRef="Gateway_0yuqj8r" />
    <sequenceFlow id="Flow_0v04kgi" name="否决" sourceRef="Gateway_0yuqj8r" targetRef="Activity_1sb5w1v">
      <conditionExpression xsi:type="tFormalExpression">${wf_reviewOutcome == 'Reject'}</conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="Flow_0dlq2m8" sourceRef="Activity_1sb5w1v" targetRef="Activity_0q8spra" />
    <sequenceFlow id="Flow_0cf866a" name="通过" sourceRef="Gateway_0yuqj8r" targetRef="Activity_0hxiyt6" />
    <exclusiveGateway id="Gateway_15wjx01" default="Flow_0am3486">
      <incoming>Flow_0qnbcun</incoming>
      <outgoing>Flow_0x8aqhn</outgoing>
      <outgoing>Flow_0am3486</outgoing>
    </exclusiveGateway>
    <sequenceFlow id="Flow_0qnbcun" sourceRef="Activity_0hxiyt6" targetRef="Gateway_15wjx01" />
    <sequenceFlow id="Flow_0x8aqhn" name="否决" sourceRef="Gateway_15wjx01" targetRef="Activity_1sb5w1v">
      <conditionExpression xsi:type="tFormalExpression">${wf_reviewOutcome == 'Reject'}</conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="Flow_0am3486" name="通过" sourceRef="Gateway_15wjx01" targetRef="Activity_0v1fbjk" />
    <exclusiveGateway id="Gateway_1xqztsb" default="Flow_0ow0dx1">
      <incoming>Flow_09v32lj</incoming>
      <outgoing>Flow_16jqt75</outgoing>
      <outgoing>Flow_0ow0dx1</outgoing>
    </exclusiveGateway>
    <sequenceFlow id="Flow_09v32lj" sourceRef="Activity_0v1fbjk" targetRef="Gateway_1xqztsb" />
    <sequenceFlow id="Flow_16jqt75" name="否决" sourceRef="Gateway_1xqztsb" targetRef="Activity_1sb5w1v">
      <conditionExpression xsi:type="tFormalExpression">${wf_reviewOutcome == 'Reject'}</conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="Flow_0ow0dx1" name="通过" sourceRef="Gateway_1xqztsb" targetRef="Event_1hgiorz" />
  </process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_1">
    <bpmndi:BPMNPlane id="contract_approve_test_di" bpmnElement="contract_approve_test">
      <bpmndi:BPMNShape id="_BPMNShape_StartEvent_1" bpmnElement="StartEvent_1">
        <omgdc:Bounds x="-18" y="322" width="36" height="36" />
        <bpmndi:BPMNLabel>
          <omgdc:Bounds x="-11" y="365" width="22" height="14" />
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="Activity_0q8spra_di" bpmnElement="Activity_0q8spra">
        <omgdc:Bounds x="70" y="300" width="100" height="80" />
        <bpmndi:BPMNLabel />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="Activity_0hxiyt6_di" bpmnElement="Activity_0hxiyt6">
        <omgdc:Bounds x="310" y="300" width="100" height="80" />
        <bpmndi:BPMNLabel />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="Activity_0v1fbjk_di" bpmnElement="Activity_0v1fbjk">
        <omgdc:Bounds x="560" y="300" width="100" height="80" />
        <bpmndi:BPMNLabel />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="Event_1hgiorz_di" bpmnElement="Event_1hgiorz">
        <omgdc:Bounds x="802" y="322" width="36" height="36" />
        <bpmndi:BPMNLabel>
          <omgdc:Bounds x="809" y="365" width="22" height="14" />
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="Activity_1sb5w1v_di" bpmnElement="Activity_1sb5w1v">
        <omgdc:Bounds x="70" y="430" width="100" height="80" />
        <bpmndi:BPMNLabel />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="Gateway_0yuqj8r_di" bpmnElement="Gateway_0yuqj8r" isMarkerVisible="true">
        <omgdc:Bounds x="205" y="315" width="50" height="50" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="Gateway_15wjx01_di" bpmnElement="Gateway_15wjx01" isMarkerVisible="true">
        <omgdc:Bounds x="445" y="315" width="50" height="50" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="Gateway_1xqztsb_di" bpmnElement="Gateway_1xqztsb" isMarkerVisible="true">
        <omgdc:Bounds x="695" y="315" width="50" height="50" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge id="Flow_1hn4w3o_di" bpmnElement="Flow_1hn4w3o">
        <omgdi:waypoint x="18" y="340" />
        <omgdi:waypoint x="70" y="340" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="Flow_02z2rrq_di" bpmnElement="Flow_02z2rrq">
        <omgdi:waypoint x="170" y="340" />
        <omgdi:waypoint x="205" y="340" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="Flow_0v04kgi_di" bpmnElement="Flow_0v04kgi">
        <omgdi:waypoint x="230" y="365" />
        <omgdi:waypoint x="230" y="470" />
        <omgdi:waypoint x="170" y="470" />
        <bpmndi:BPMNLabel>
          <omgdc:Bounds x="234" y="415" width="22" height="14" />
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="Flow_0dlq2m8_di" bpmnElement="Flow_0dlq2m8">
        <omgdi:waypoint x="120" y="430" />
        <omgdi:waypoint x="120" y="380" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="Flow_0cf866a_di" bpmnElement="Flow_0cf866a">
        <omgdi:waypoint x="255" y="340" />
        <omgdi:waypoint x="310" y="340" />
        <bpmndi:BPMNLabel>
          <omgdc:Bounds x="272" y="322" width="22" height="14" />
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="Flow_0qnbcun_di" bpmnElement="Flow_0qnbcun">
        <omgdi:waypoint x="410" y="340" />
        <omgdi:waypoint x="445" y="340" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="Flow_0x8aqhn_di" bpmnElement="Flow_0x8aqhn">
        <omgdi:waypoint x="470" y="365" />
        <omgdi:waypoint x="470" y="470" />
        <omgdi:waypoint x="170" y="470" />
        <bpmndi:BPMNLabel>
          <omgdc:Bounds x="474" y="415" width="22" height="14" />
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="Flow_0am3486_di" bpmnElement="Flow_0am3486">
        <omgdi:waypoint x="495" y="340" />
        <omgdi:waypoint x="560" y="340" />
        <bpmndi:BPMNLabel>
          <omgdc:Bounds x="517" y="322" width="22" height="14" />
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="Flow_09v32lj_di" bpmnElement="Flow_09v32lj">
        <omgdi:waypoint x="660" y="340" />
        <omgdi:waypoint x="695" y="340" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="Flow_16jqt75_di" bpmnElement="Flow_16jqt75">
        <omgdi:waypoint x="720" y="365" />
        <omgdi:waypoint x="720" y="470" />
        <omgdi:waypoint x="170" y="470" />
        <bpmndi:BPMNLabel>
          <omgdc:Bounds x="724" y="415" width="22" height="14" />
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="Flow_0ow0dx1_di" bpmnElement="Flow_0ow0dx1">
        <omgdi:waypoint x="745" y="340" />
        <omgdi:waypoint x="802" y="340" />
        <bpmndi:BPMNLabel>
          <omgdc:Bounds x="763" y="322" width="22" height="14" />
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

# 激活流程

回到 工作流程 页面,将流程的状态改为:“激活”

# 7、为站点配置流程

回到 合同管理 站点,点击 站点设置,将流程绑定到站点上

# 8、验证

# 上传

切换用户:林毅

进入 合同站点 > 文档库 > 2023年,上传一笔合同文件

验证:此时合同文件状态为“草稿”

# 发起申请

选中待审批的合同文件,点击 发起流程 > 合同审批

填写表单,合同确认人员选择:许志宏,点击 提交审批

# 审批

切换用户:许志宏

进入 我的任务 > 我的待办,点击任务进入审批表单,对审批表单进行处理

依次切换用户:杨先壮、张伟华、蔡春辉,验证审批流程

# 结束

审批通过后,回到 合同审批 站点,此时合同状态变更为:已审批。

更新时间: 2023年4月8日星期六中午11点45分