动态任务分配仿真实现

动态任务分配使用的两种方式

转载:https://blog.csdn.net/wei763328075qq/article/details/51596621

一、通过特殊表达式,来获取任务信息 ,在流程 UserTask节点上设置 ${流程变量的Key}

1、流程定义

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" 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" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/test">
 3   <process id="userDynamicTask1" name="动态任务处理1" isExecutable="true">
 4     <startEvent id="startevent1" name="Start"></startEvent>
 5     <userTask id="休假" name="休假" activiti:assignee="${user}"></userTask>
 6     <sequenceFlow id="flow1" sourceRef="startevent1" targetRef="休假"></sequenceFlow>
 7     <endEvent id="endevent1" name="End"></endEvent>
 8     <sequenceFlow id="flow2" sourceRef="休假" targetRef="endevent1"></sequenceFlow>
 9   </process>
10   <bpmndi:BPMNDiagram id="BPMNDiagram_userDynamicTask1">
11     <bpmndi:BPMNPlane bpmnElement="userDynamicTask1" id="BPMNPlane_userDynamicTask1">
12       <bpmndi:BPMNShape bpmnElement="startevent1" id="BPMNShape_startevent1">
13         <omgdc:Bounds height="35.0" width="35.0" x="340.0" y="110.0"></omgdc:Bounds>
14       </bpmndi:BPMNShape>
15       <bpmndi:BPMNShape bpmnElement="休假" id="BPMNShape_休假">
16         <omgdc:Bounds height="55.0" width="105.0" x="305.0" y="180.0"></omgdc:Bounds>
17       </bpmndi:BPMNShape>
18       <bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1">
19         <omgdc:Bounds height="35.0" width="35.0" x="340.0" y="270.0"></omgdc:Bounds>
20       </bpmndi:BPMNShape>
21       <bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1">
22         <omgdi:waypoint x="357.0" y="145.0"></omgdi:waypoint>
23         <omgdi:waypoint x="357.0" y="180.0"></omgdi:waypoint>
24       </bpmndi:BPMNEdge>
25       <bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2">
26         <omgdi:waypoint x="357.0" y="235.0"></omgdi:waypoint>
27         <omgdi:waypoint x="357.0" y="270.0"></omgdi:waypoint>
28       </bpmndi:BPMNEdge>
29     </bpmndi:BPMNPlane>
30   </bpmndi:BPMNDiagram>
31 </definitions>

View Code

2、发布流程

 1 /**
 2      * 2、发布一个流程:发布通过特殊表达式,来获取任务信息  ${流程变量的Key}的流程
 3      */
 4     @Test
 5     public void  testDeployProcess() {
 6         RepositoryService repositoryService = processEngine.getRepositoryService();
 7         DeploymentBuilder builder = repositoryService.createDeployment();
 8         // 加载发布资源
 9         builder.name("动态任务处理流程1-测试") // 设置流程显示别名
10                 .addClasspathResource("leave3.bpmn") // 设置流程规则文件
11                 .addClasspathResource("leave3.png"); // 设置流程规则的图片
12         // 发布流程
13         builder.deploy();
14     }

View Code

3、启动与测试流程

 1     
 2     /**
 3      * 3、启动流程、执行任务,并查看状态
 4      */
 5     @Test
 6     public void testUserTask() {        
 7         // 获取RuntimeService服务对象的实例
 8         RuntimeService runtimeService = processEngine.getRuntimeService();
 9         String processDefinitionKey = "userDynamicTask1";
10         // 自动执行与Key相对应的流程的最高版本
11         Map<String, Object> variables = new HashMap<String, Object>();
12         //variables.put("user", "张三");
13         variables.put("user", "李四");
14         
15         ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionKey,variables);        
16         String processInstanceId = processInstance.getId();        
17         logger.info("processInstanceId:" + processInstance.getId());
18         
19         // 获取TaskService服务对象的实例
20         TaskService taskService = processEngine.getTaskService();
21         //String assignee = "张三";
22         String assignee = "李四";
23         List<Task> tasks = taskService.createTaskQuery().taskAssignee(assignee).list();
24         Assert.assertEquals(1, tasks.size());
25         Task task = tasks.get(0);        
26         logger.info("taskName:" + task.getName());
27         logger.info("taskAssignee:" + task.getAssignee());
28         Assert.assertEquals("休假",task.getName());
29         
30         //完成任务
31         taskService.complete(task.getId());        
32         
33         //检查结束状态
34         ProcessInstance pInstance = runtimeService
35                                                         .createProcessInstanceQuery()
36                                                         .processInstanceId(processInstanceId)
37                                                         .singleResult();
38         Assert.assertNull(pInstance);
39         logger.info("动态任务处理流程1,使用${流程变量的Key}方式成功执行!");        
40         
41     }

View Code

4、运行结果

[INFO][2015-12-02 11:44:05,129][com.mcs.activiti.test.TestUserTaskDynamic]processInstanceId:130001
[INFO][2015-12-02 11:44:05,159][com.mcs.activiti.test.TestUserTaskDynamic]taskName:休假
[INFO][2015-12-02 11:44:05,159][com.mcs.activiti.test.TestUserTaskDynamic]taskAssignee:李四
[INFO][2015-12-02 11:44:05,456][com.mcs.activiti.test.TestUserTaskDynamic]动态任务处理流程1,使用${流程变量的Key}方式成功执行!

二、使用任务分配处理器

1、自定义任务分配处理器步骤

  1.1、  创建一个类来充分“任务分配处理器”,需要实现TaskListener

  1.2、  在实现方式中添加响应的处理逻辑;

  1.3、  在流程中,配置/使用任务处理器。

2、创建自定义任务分配处理器,实现TaskListener

 1 package mcs.listener;
 2 
 3 import org.activiti.engine.delegate.DelegateTask;
 4 import org.activiti.engine.delegate.TaskListener;
 5 
 6 public class ManagerTaskListenerHandler implements TaskListener {
 7 
 8     private static final long serialVersionUID = 1L;
 9 
10     @Override
11     public void notify(DelegateTask delegateTask) {
12         String assignee = "王五";
13         delegateTask.setAssignee(assignee);
14         
15         //delegateTask.addCandidateUser("王小二");
16     }
17 
18 }

View Code

3、流程定义

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" 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" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/test">
 3   <process id="userDynamicTask2" name="动态任务处理2" isExecutable="true">
 4     <startEvent id="startevent1" name="Start"></startEvent>
 5     <endEvent id="endevent1" name="End"></endEvent>
 6     <userTask id="休假" name="休假">
 7       <extensionElements>
 8         <activiti:taskListener event="create" class="mcs.listener.ManagerTaskListenerHandler"></activiti:taskListener>
 9       </extensionElements>
10     </userTask>
11     <sequenceFlow id="flow1" sourceRef="startevent1" targetRef="休假"></sequenceFlow>
12     <sequenceFlow id="flow2" sourceRef="休假" targetRef="endevent1"></sequenceFlow>
13   </process>
14   <bpmndi:BPMNDiagram id="BPMNDiagram_userDynamicTask2">
15     <bpmndi:BPMNPlane bpmnElement="userDynamicTask2" id="BPMNPlane_userDynamicTask2">
16       <bpmndi:BPMNShape bpmnElement="startevent1" id="BPMNShape_startevent1">
17         <omgdc:Bounds height="35.0" width="35.0" x="340.0" y="110.0"></omgdc:Bounds>
18       </bpmndi:BPMNShape>
19       <bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1">
20         <omgdc:Bounds height="35.0" width="35.0" x="340.0" y="270.0"></omgdc:Bounds>
21       </bpmndi:BPMNShape>
22       <bpmndi:BPMNShape bpmnElement="休假" id="BPMNShape_休假">
23         <omgdc:Bounds height="55.0" width="105.0" x="305.0" y="180.0"></omgdc:Bounds>
24       </bpmndi:BPMNShape>
25       <bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1">
26         <omgdi:waypoint x="357.0" y="145.0"></omgdi:waypoint>
27         <omgdi:waypoint x="357.0" y="180.0"></omgdi:waypoint>
28       </bpmndi:BPMNEdge>
29       <bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2">
30         <omgdi:waypoint x="357.0" y="235.0"></omgdi:waypoint>
31         <omgdi:waypoint x="357.0" y="270.0"></omgdi:waypoint>
32       </bpmndi:BPMNEdge>
33     </bpmndi:BPMNPlane>
34   </bpmndi:BPMNDiagram>
35 </definitions>

View Code

4、发布流程

 1 /**
 2      * 4、发布一个流程:发布通过自定义任务分配处理器的流程
 3      *         自定义任务分配处理器步骤:
 4      *         1、创建一个类来充分“任务分配处理器”,需要实现TaskListener
 5     *        2、在实现方式中添加响应的处理逻辑;
 6     *        3、在流程中,配置/使用任务处理器。
 7      */
 8     @Test
 9     public void  testDeployProcess2() {
10         RepositoryService repositoryService = processEngine.getRepositoryService();
11         DeploymentBuilder builder = repositoryService.createDeployment();
12         // 加载发布资源
13         builder.name("动态任务处理流程2-测试") // 设置流程显示别名
14                 .addClasspathResource("leave4.bpmn") // 设置流程规则文件
15                 .addClasspathResource("leave4.png"); // 设置流程规则的图片
16         // 发布流程
17         builder.deploy();
18     }
19     

View Code

5、启动与测试流程

 1     /**
 2      * 5、启动流程、执行任务,并查看状态
 3      */
 4     @Test
 5     public void testUserTask2() {        
 6         // 获取RuntimeService服务对象的实例
 7         RuntimeService runtimeService = processEngine.getRuntimeService();
 8         String processDefinitionKey = "userDynamicTask2";
 9         // 自动执行与Key相对应的流程的最高版本    
10         ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionKey);        
11         String processInstanceId = processInstance.getId();        
12         logger.info("processInstanceId:" + processInstance.getId());
13         
14         // 获取TaskService服务对象的实例
15         TaskService taskService = processEngine.getTaskService();
16         String assignee = "王五";
17         List<Task> tasks = taskService.createTaskQuery().taskAssignee(assignee).list();
18         Assert.assertEquals(1, tasks.size());
19         Task task = tasks.get(0);        
20         logger.info("taskName:" + task.getName());
21         logger.info("taskAssignee:" + task.getAssignee());
22         Assert.assertEquals("休假",task.getName());
23         
24         //完成任务
25         taskService.complete(task.getId());        
26         
27         //检查结束状态
28         ProcessInstance pInstance = runtimeService
29                                                         .createProcessInstanceQuery()
30                                                         .processInstanceId(processInstanceId)
31                                                         .singleResult();
32         Assert.assertNull(pInstance);
33         logger.info("动态任务处理流程2,使用自定义任务分配处理器方式成功执行!");        
34         
35     }

View Code

6、运行结果

[INFO][2015-12-02 11:46:51,818][com.mcs.activiti.test.TestUserTaskDynamic]processInstanceId:132501
[INFO][2015-12-02 11:46:51,879][com.mcs.activiti.test.TestUserTaskDynamic]taskName:休假
[INFO][2015-12-02 11:46:51,879][com.mcs.activiti.test.TestUserTaskDynamic]taskAssignee:王五
[INFO][2015-12-02 11:46:52,192][com.mcs.activiti.test.TestUserTaskDynamic]动态任务处理流程2,使用自定义任务分配处理器方式成功执行!

activiti 动态分配任务候选人

转载:https://blog.csdn.net/ldqchat/article/details/81866073

任务候选人是有权限对该任务进行操作的用户,
    可以使用TaskService.addCandidateUser() 或 addCandidateGroup()实现,
    可以在bpmn中进行配置,
    可以使用监听器方式(需要继承TaskListener)
    可以使用JUEL表达式实现,使用${}来引用,和EL表达式一样
 
下面我们使用JUEL表达式实现:
1. 在bpmn中引用类:
 
<process id="leaveBill" name="leaveBillprocess" isExecutable="true">
    <startEvent id="startevent1" name="Start"></startEvent>
    <endEvent id="endevent1" name="End"></endEvent>
    <userTask id="usertask1" name="User Task"     activiti:candidateUsers="${authService.getCandidateUsers()}"></userTask>
    <sequenceFlow id="flow3" sourceRef="usertask1" targetRef="endevent1"></sequenceFlow>
    <userTask id="usertask2" name="User Task"></userTask>
    <sequenceFlow id="flow4" sourceRef="startevent1" targetRef="usertask2"></sequenceFlow>
    <sequenceFlow id="flow5" sourceRef="usertask2" targetRef="usertask1"></sequenceFlow>
  </process>
...
 
2. 定义获取用户的类,要序列化
public class AuthService implements Serializable  {
    public List<String> getCandidateUsers(){
        List<String> users=new ArrayList<>();
        users.add("user1");
        users.add("user2");
        return users;
    }
    
}
 
3. 在流程中传入引用类
 
RuntimeService runtimeService = engine.getRuntimeService();
Deployment de = rs.createDeployment().addClasspathResource("test.bpmn").deploy();
Map<String,Object> vars=new HashMap<>();
vars.put("authService", new AuthService());
ProcessInstance pi =     
    runtimeService.startProcessInstanceByKey(de.getKey(),vars);
List<Task> list2 = taskService.createTaskQuery().taskCandidateUser("user1").list();
List<Task> list2 = taskService.createTaskQuery().taskCandidateUser("user2").list();

activiti个人任务分配,动态指定和监听器指定任务委派人

转载:https://blog.csdn.net/csdnliuxin123524/article/details/80067360

这章我们介绍下怎么把任务非配给指定的某个人去执行。现实使用的时候我们也有见过前面一个人审批结束后会自动走到下一个审批人,如果不处理就会一直等待,这里也是同样的道理。

这里先把任务分配给xiaoliu001,也就是写死指定某个人

代码如下:

package com.xiaoyexinxixn.ActivityLesson.flow;
 
 
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.junit.Test;
 
import com.xiaoyexinxixn.ActivityLesson.model.Student;
 
public class StudentLeaveProcess10 {
    //获取默认流程引擎实例,会自动读取activiti.cfg.xml ,所以我们要严格定义配置文件的名称
    private ProcessEngine processEngine =ProcessEngines.getDefaultProcessEngine();
    
    /**
     * 部署流程定义
     */
    @Test
    public void deploy() {
        //获取部署相关service,这些都是activiti封装好的api接口,还有很多,下面也会用到很多
        Deployment deployment=processEngine.getRepositoryService()
        //创建部署
        .createDeployment()
        //加载流程图资源文件
        .addClasspathResource("diagrams/StudentLeave10.bpmn")
        //加载流程图片
        .addClasspathResource("diagrams/StudentLeave10.png")
        //流程名称
        .name("leave10")
        //部署流程
        .deploy();
        System.out.println("流程部署的ID: "+deployment.getId());
        System.out.println("流程部署的Name: "+deployment.getName());
    }
    
    /*
     * 启动流程实例
     */
    @Test
    public void start(){
        //运行启动流程的servicee
        ProcessInstance pi=processEngine.getRuntimeService()
        //定义流程表的KEY字段值,key值是我们前面定义好的key,可在act_re_procdef表中的key_字段中找到,
        .startProcessInstanceByKey("StudentLeaveProcess10");
        System.out.println(pi.getId());
        System.out.println(pi.getProcessDefinitionId());
    }
    
    /**
     * 查看任务
     */
    @Test
    public void findTaskList(){
        //获取任务列表的service
        List<Task> taskList=processEngine.getTaskService()
                //创建任务查询
                .createTaskQuery()
                //指定任务的执行人
                .taskAssignee("xiaoliu001")
                .list();
        for(Task task:taskList){
            System.out.println("任务ID:"+task.getId());
            System.out.println("任务名称:"+task.getName());
            System.out.println("任务创建时间:"+task.getCreateTime());
            System.out.println("任务委派人:"+task.getAssignee());
            System.out.println("任务流程实例Id:"+task.getProcessInstanceId());
        }
    }

依次执行上面的方法,在最后的查看任务方法的结果是:

任务ID:160004
任务名称:leave001
任务创建时间:Tue Apr 24 17:19:17 CST 2018
任务委派人:xiaoliu001
任务流程实例Id:160001

说明是OK的,这也是最简单的一种了。

 

下面是用流程变量动态指定任务委派人:

流程图稍作修改,如下,使用表达式,下面代码中会指定这个变量的值是多少:

 package com.xiaoyexinxixn.ActivityLesson.flow;
 
 
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.junit.Test;
 
import com.xiaoyexinxixn.ActivityLesson.model.Student;
 
public class StudentLeaveProcess10 {
    //获取默认流程引擎实例,会自动读取activiti.cfg.xml ,所以我们要严格定义配置文件的名称
    private ProcessEngine processEngine =ProcessEngines.getDefaultProcessEngine();
    
    /**
     * 部署流程定义
     */
    @Test
    public void deploy() {
        //获取部署相关service,这些都是activiti封装好的api接口,还有很多,下面也会用到很多
        Deployment deployment=processEngine.getRepositoryService()
        //创建部署
        .createDeployment()
        //加载流程图资源文件
        .addClasspathResource("diagrams/StudentLeave10.bpmn")
        //加载流程图片
        .addClasspathResource("diagrams/StudentLeave10.png")
        //流程名称
        .name("leave10")
        //部署流程
        .deploy();
        System.out.println("流程部署的ID: "+deployment.getId());
        System.out.println("流程部署的Name: "+deployment.getName());
    }
    
    /*
     * 启动流程实例
     */
    @Test
    public void start(){
        //流程启动时设置流程比那里,指定执行人
        Map<String, Object> variables=new HashMap<String,Object>();
        variables.put("userId", "xiaoliu002");
        //运行启动流程的servicee
        ProcessInstance pi=processEngine.getRuntimeService()
        //定义流程表的KEY字段值,key值是我们前面定义好的key,可在act_re_procdef表中的key_字段中找到,
        .startProcessInstanceByKey("StudentLeaveProcess10",variables);
        System.out.println(pi.getId());
        System.out.println(pi.getProcessDefinitionId());
    }
    
    /**
     * 查看任务
     */
    @Test
    public void findTaskList(){
        //获取任务列表的service
        List<Task> taskList=processEngine.getTaskService()
                //创建任务查询
                .createTaskQuery()
                //指定任务的执行人
                .taskAssignee("xiaoliu002")
                .list();
        for(Task task:taskList){
            System.out.println("任务ID:"+task.getId());
            System.out.println("任务名称:"+task.getName());
            System.out.println("任务创建时间:"+task.getCreateTime());
            System.out.println("任务委派人:"+task.getAssignee());
            System.out.println("任务流程实例Id:"+task.getProcessInstanceId());
        }
    }

依次执行上面代码,最后查看任务可以看出流程的执行人已经是xiaoliu002了。

使用监听器设置执行人:

首先写一个监听器类:

package com.xiaoyexinxixn.ActivityLesson;
 
import org.activiti.engine.delegate.DelegateTask;
import org.activiti.engine.delegate.TaskListener;
 
public class MyTaskListener implements TaskListener{
 
    @Override
    public void notify(DelegateTask delegateTask) {//DelegateTask 代理任务对象
        // TODO Auto-generated method stub
        delegateTask.setAssignee("liu001");//指定办理人
//        delegateTask.addCandidateUser("liu002");
    }
 
}

然后再复制一个流程图,做如下修改,把我们刚才新建的类放进去

完了再写测试类:

package com.xiaoyexinxixn.ActivityLesson.flow;
 
 
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.junit.Test;
 
import com.xiaoyexinxixn.ActivityLesson.model.Student;
 
public class StudentLeaveProcess11 {
    //获取默认流程引擎实例,会自动读取activiti.cfg.xml ,所以我们要严格定义配置文件的名称
    private ProcessEngine processEngine =ProcessEngines.getDefaultProcessEngine();
    
    /**
     * 部署流程定义
     */
    @Test
    public void deploy() {
        //获取部署相关service,这些都是activiti封装好的api接口,还有很多,下面也会用到很多
        Deployment deployment=processEngine.getRepositoryService()
        //创建部署
        .createDeployment()
        //加载流程图资源文件
        .addClasspathResource("diagrams/StudentLeave11.bpmn")
        //加载流程图片
        .addClasspathResource("diagrams/StudentLeave11.png")
        //流程名称
        .name("leave11")
        //部署流程
        .deploy();
        System.out.println("流程部署的ID: "+deployment.getId());
        System.out.println("流程部署的Name: "+deployment.getName());
    }
    
    /*
     * 启动流程实例
     */
    @Test
    public void start(){
        //运行启动流程的servicee
        ProcessInstance pi=processEngine.getRuntimeService()
        //定义流程表的KEY字段值,key值是我们前面定义好的key,可在act_re_procdef表中的key_字段中找到,
        .startProcessInstanceByKey("StudentLeaveProcess11");
        System.out.println(pi.getId());
        System.out.println(pi.getProcessDefinitionId());
    }
    
    /**
     * 查看任务
     */
    @Test
    public void findTaskList(){
        //获取任务列表的service
        List<Task> taskList=processEngine.getTaskService()
                //创建任务查询
                .createTaskQuery()
                //指定任务的执行人
                .taskAssignee("liu001")
                .list();
        for(Task task:taskList){
            System.out.println("任务ID:"+task.getId());
            System.out.println("任务名称:"+task.getName());
            System.out.println("任务创建时间:"+task.getCreateTime());
            System.out.println("任务委派人:"+task.getAssignee());
            System.out.println("任务流程实例Id:"+task.getProcessInstanceId());
        }
    }}

最后的查看任务方法也是有数据的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值