首页 > 其他分享 >客户生命周期流程设计

客户生命周期流程设计

时间:2022-12-06 17:44:45浏览次数:34  
标签:COMMENT 生命周期 varchar DEFAULT 流程 客户 nodeItem NULL 节点

需求:

  记录一个客户从注册到注销经历的各个生命周期节点,给与查询展示

设计:

  1、生命周期节点分为以下几个流程:注册、授信、资料获取...(先开发部分流程,剩余用...表示)流程只有特定流程有顺序,有些流程是交叉进行的,比如授信和资料获取

  2、生命周期节点主要信息是:描述、所属流程、失败原因、触发时间    节点有:开始节点、结束节点、流程唯一节点    默认一个流程内节点是可重复的,例如,审核拒绝->补件->审核拒绝->补件->审核成功这种操作     流程唯一节点是在这样的场景:决策提交前,每2分钟查询一次最新征信数据等,不管成功失败都查询  最新不通过无法提交决策,这种数据要求展示最新一次的节点数据,不是连接操作。 有些节点是各个流程公用的,例如税务授权,授信、提额都需要税务授权,针对这种目前是作为公共节点,直挂用户,下一个流程产生时挂载到流程

  

设计图:

 

 

 

 

 

 

 

 

数据库表:

-- 生命周期表 begin
CREATE TABLE `supply_chain_dsc`.`scp_dsc_cust_life_cycle_process_node_item` (
  `id` bigint(11) NOT NULL AUTO_INCREMENT,
  `item_no` varchar(20) NOT NULL COMMENT '节点条目编码',
  `process_no` varchar(20) DEFAULT NULL COMMENT '所属流程编码',
  `node_no` varchar(20) NOT NULL COMMENT '节点编码',
  `node_desc` varchar(50) NOT NULL COMMENT '节点描述',
  `result_no` varchar(50) NOT NULL COMMENT '节点结果',
  `result_desc` varchar(100) DEFAULT NULL COMMENT '节点条目描述',
  `is_start_node` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否开始节点:0-否、1-是',
  `is_complete_node` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否完成节点:0-否、1-是',
  `is_process_unique`  tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否流程唯一:0-否、1-是',
  `is_deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否删除:0-否、1-是',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='用户生命周期流程节点表';

CREATE TABLE `supply_chain_dsc`.`scp_dsc_cust_life_cycle_process_node_record` (
  `id` bigint(11) NOT NULL AUTO_INCREMENT,
  `process_record_id` bigint(11) DEFAULT NULL COMMENT '进程记录id',
  `life_cycle_record_id` bigint(20) NOT NULL COMMENT '生命周期记录id',
  `process_no` varchar(20) NOT NULL COMMENT '进程编码',
  `process_node_no` varchar(20) NOT NULL COMMENT '进程节点编码',
  `process_node_desc` varchar(50) NOT NULL COMMENT '进程节点描述',
  `process_node_item_no` varchar(20) DEFAULT NULL COMMENT '流程节点条目编码',
  `process_node_result` varchar(50) DEFAULT NULL COMMENT '流程节点结果',
  `completed_time` datetime NOT NULL COMMENT '完成时间',
  `fail_reason` varchar(500) DEFAULT NULL COMMENT '失败原因',
  `remark` varchar(255) DEFAULT NULL COMMENT '备注字段',
  `is_invalid` tinyint(1) DEFAULT '0' COMMENT '是否失效:0-否、1-是',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建日期',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新日期',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='生命周期进程节点记录表';

CREATE TABLE `supply_chain_dsc`.`scp_dsc_cust_life_cycle_process_record` (
  `id` bigint(11) NOT NULL AUTO_INCREMENT,
  `life_cycle_record_id` int(11) NOT NULL COMMENT '用户生命周期id',
  `process_special_business_data` varchar(2000) DEFAULT '' COMMENT '流程专属业务数据,json。 不同流程结构不一致',
  `process_no` varchar(20) NOT NULL COMMENT '流程编码',
  `process_desc` varchar(50) NOT NULL COMMENT '流程描述',
  `is_invalid` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否失效:0-否、1-是',
  `is_completed` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否完成:0-否、1-是',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建日期',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新日期',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='用户生命周期流程记录表';

CREATE TABLE `supply_chain_dsc`.`scp_dsc_cust_life_cycle_record` (
  `id` bigint(11) unsigned NOT NULL AUTO_INCREMENT,
  `user_id` varchar(12) NOT NULL COMMENT '用户id',
  `certificate_no` varchar(30) DEFAULT NULL COMMENT '证件号码',
  `certificate_type` varchar(2) DEFAULT NULL COMMENT '证件类型 01-身份证号、02-社会信用代码',
  `project_id` varchar(50) DEFAULT NULL COMMENT '项目id',
  `project_name` varchar(64) DEFAULT NULL COMMENT '项目名称',
  `cust_name` varchar(128) DEFAULT NULL COMMENT '客户名称',
  `related_party_name` varchar(128) DEFAULT NULL COMMENT '关联方名称',
  `process_node_item_no` varchar(20) NOT NULL COMMENT '当前流程节点编码',
  `process_no` varchar(20) NOT NULL COMMENT '当前流程编码',
  `process_node_desc` varchar(50) DEFAULT NULL COMMENT '当前节点描述',
  `is_show` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否展示:0-否、1-是',
  `register_time` datetime NOT NULL COMMENT '注册时间',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='用户生命周期记录表';

 

主要代码:

1、接收对象转存储对象

/**
 * 生命周期节点结果Mq接收
 * @author zhen
 * @date 2022/11/28 9:16
 * @description
 */
@Data
public class LifeCycleNodeResultMqEvent implements Serializable {
    /**
     * 节点Item编码 必填
     */
    private String processNodeItemNo;

    /**
     * 完成时间: yyyy-MM-dd HH:mm:ss  必填
     */
    private String completeTime;

    /**
     * 失败原因
     */
    private String failReason;

    /**
     * 项目id 除了注册流程指定节点之外,必填
     */
    private String projectId;

    /**
     * 证件类型: 01-身份证号、02-社会信用代码  除了注册流程指定节点之外,必填
     */
    private String certificateType;

    /**
     * 证件号 除了注册流程指定节点之外,必填
     */
    private String certificateNo;

    /**
     * 节点属性json
     */
    private String processPropertyJson;
}

/**
 * 注册流程属性event
 * @author zhen
 * @date 2022/11/28 9:35
 * @description
 */
@Data
public class LifeCycleRegisterProcessPropertyEvent implements Serializable {

    /**
     * 手机号
     */
    private String phone;
    /**
     * 用户id
     */
    private String userId;
    /**
     * 身份证号
     */
    private String idCardNo;

    /**
     * 用户姓名
     */
    private String userName;

    /**
     * 企业名称
     */
    private String enterpriseName;

}

/**
 * 注册流程数据Template
 * @author zhen
 * @date 2022/11/28 9:35
 * @description
 */
@Data
public class LifeCycleRegisterProcessDataTemplate implements Serializable {

    /**
     * 手机号
     */
    private String phone;
    /**
     * 用户id
     */
    private String userId;
    /**
     * 身份证号
     */
    private String idCardNo;

    /**
     * 用户姓名
     */
    private String userName;

}

 

核心代码:

@Override
    @Transactional(rollbackFor = Exception.class)
    public void receiptProcessNodeResult(LifeCycleNodeResultMqEvent event) {

        CustLifeCycleProcessNodeItem nodeItem = lifeCycleProcessNodeItemService.findByNodeItemNo(event.getProcessNodeItemNo());

        if (nodeItem == null) {
            log.info("【客户生命周期】根据节点item编号找不到对应的属性节点 nodeItemNo:{}", event.getProcessNodeItemNo());
            return;
        }

        if(ProcessSpecialNodeItemEnum.isValidValue(nodeItem.getItemNo())){
            nodeSpecialDeal(nodeItem, event);
        }else {
            normalNodeDeal(nodeItem, event);
        }

    }


    private String transProcessDataEventValueToTemplateValue(String eventValueJson, String processNo){
        if (StringUtils.isEmpty(eventValueJson) || "{}".equals(eventValueJson)){
            return "{}";
        }
        ProcessTemplateTransEnum templateTransEnum = ProcessTemplateTransEnum.getByValue(processNo);
        if (templateTransEnum != null) {
            try{
                Class srcClazz = Class.forName(templateTransEnum.getSrcClazzName());
                Class targetClazz = Class.forName(templateTransEnum.getSrcClazzName());
                Object srcObj = JSON.parseObject(eventValueJson, srcClazz);
                Object targetObject = targetClazz.newInstance();
                BeanUtils.copyProperties(srcObj, targetObject);
                return JSON.toJSONString(targetObject);
            } catch (IllegalAccessException|InstantiationException|ClassNotFoundException e) {
                log.error("对象转换异常", e);
                throw new RuntimeException("客户生命周期流程对象转换异常");
            }

        }
        return "{}";
    }

    private void nodeSpecialDeal(CustLifeCycleProcessNodeItem nodeItem, LifeCycleNodeResultMqEvent event){
        Class<LifeCycleNodeItemReceiptBusinessImpl> clazz = LifeCycleNodeItemReceiptBusinessImpl.class;
        try{
            Method invokeMethod = clazz.getMethod("n" + nodeItem.getItemNo() + "Deal", CustLifeCycleProcessNodeItem.class, LifeCycleNodeResultMqEvent.class);
            invokeMethod.invoke(this, nodeItem, event);
        }catch (NoSuchMethodException|IllegalAccessException|InvocationTargetException e) {
            log.error("【LEVEL:LOW】找不到处理此特殊节点结果的执行器, 节点结果编码:{}", nodeItem.getItemNo());
            return;
        }
    }

    /**
     * 常用节点处理
     * @param nodeItem
     * @param event
     */
    private void normalNodeDeal(CustLifeCycleProcessNodeItem nodeItem, LifeCycleNodeResultMqEvent event) {

        CustLifeCycleRecord nodeLifeCycleRecord = getLifeCycleRecordByBusinessPk(event);
        if (nodeLifeCycleRecord == null) {
            return;
        }

        normalNodeDealUseLifeCycle(nodeLifeCycleRecord, nodeItem, event);
    }

    /**
     * 已知生命周期情况下常用节点处理
     * @param nodeLifeCycleRecord
     * @param nodeItem
     * @param event
     */
    private void normalNodeDealUseLifeCycle(CustLifeCycleRecord nodeLifeCycleRecord, CustLifeCycleProcessNodeItem nodeItem, LifeCycleNodeResultMqEvent event){
        //生命周期记录更新
        normalLifeCycleUpdate(nodeLifeCycleRecord, nodeItem);

        CustLifeCycleProcessRecord processRecord = lifeCycleProcessRecordService.selectCurrentProcessRecord(nodeLifeCycleRecord.getId(), nodeItem.getProcessNo());

        //节点保存
        nodeItemSave(nodeLifeCycleRecord.getId(), processRecord == null ? null : processRecord.getId(), nodeItem, event);
    }

    /**
     * 公用节点挂载
     * @param processRecord
     */
    private void commonNodeMount(CustLifeCycleProcessRecord processRecord ){
        List<CustLifeCycleProcessNodeRecord> nodeRecordList = lifeCycleProcessNodeRecordService.selectUnMountNodeRecordList(processRecord.getLifeCycleRecordId());
        for (CustLifeCycleProcessNodeRecord nodeRecord : nodeRecordList) {
            nodeRecord.setProcessNo(processRecord.getProcessNo());
            nodeRecord.setProcessRecordId(processRecord.getId());
        }
        lifeCycleProcessNodeRecordService.updateBatchById(nodeRecordList);
    }

    /**
     * 常用的生命周期更新操作
     * @param lifeCycleRecord
     * @param nodeItem
     */
    private void normalLifeCycleUpdate(CustLifeCycleRecord lifeCycleRecord, CustLifeCycleProcessNodeItem nodeItem){
        lifeCycleRecord.setProcessNo(nodeItem.getProcessNo());
        lifeCycleRecord.setProcessNodeDesc(nodeItem.getNodeDesc());
        lifeCycleRecord.setProcessNodeItemNo(nodeItem.getItemNo());
        lifeCycleRecord.setUpdateTime(LocalDateTime.now());
        lifeCycleRecordService.updateById(lifeCycleRecord);
    }

    /**
     * 常用的保存节点操作
     * @param lifeCycleRecordId
     * @param processRecordId
     * @param nodeItem
     * @param event
     */
    private void nodeItemSave(Long lifeCycleRecordId, Long processRecordId, CustLifeCycleProcessNodeItem nodeItem, LifeCycleNodeResultMqEvent event) {
        CustLifeCycleProcessRecord processRecord = null;
        if (processRecordId == null) {
            if (nodeItem.getIsStartNode() == 1) {
                //创建流程记录
                processRecord = buildNormalProcessRecord(lifeCycleRecordId, nodeItem);
                processRecord.setProcessSpecialBusinessData(transProcessDataEventValueToTemplateValue(event.getProcessPropertyJson(), nodeItem.getProcessNo()));
                lifeCycleProcessRecordService.save(processRecord);
            }
        }else {
            processRecord = lifeCycleProcessRecordService.getById(processRecordId);
        }
        if (processRecord != null){
            processRecordId = processRecord.getId();
            //公用节点挂载
            commonNodeMount(processRecord);
            /*
             * 完成节点特殊处理
             */
            if (1 == nodeItem.getIsCompleteNode()) {
                //0 -否、1-是 公用节点不可能是完成节点,因此,不会出现空指针
                processRecord.setIsCompleted(1);
                lifeCycleProcessRecordService.updateById(processRecord);
            }
        }


        if(nodeItem.getIsProcessUnique() == 1){
            //保存最新记录的节点操作就死update最新信息
            CustLifeCycleProcessNodeRecord processNoRecord = lifeCycleProcessNodeRecordService.findProcessNoRecord(lifeCycleRecordId, processRecordId, nodeItem.getItemNo());
            if (processNoRecord != null){
                CustLifeCycleProcessNodeRecord nodeRecord = buildNormalUpdateProcessNodeRecord(processNoRecord, event);
                lifeCycleProcessNodeRecordService.updateById(nodeRecord);
            }else {
                CustLifeCycleProcessNodeRecord nodeRecord = buildNormalProcessNodeRecord(lifeCycleRecordId, processRecordId, nodeItem, event);
                lifeCycleProcessNodeRecordService.save(nodeRecord);
            }
        }else {
            CustLifeCycleProcessNodeRecord nodeRecord = buildNormalProcessNodeRecord(lifeCycleRecordId, processRecordId, nodeItem, event);
            lifeCycleProcessNodeRecordService.save(nodeRecord);
        }

    }
View Code

 

 

 

 

 

 

  

标签:COMMENT,生命周期,varchar,DEFAULT,流程,客户,nodeItem,NULL,节点
From: https://www.cnblogs.com/aigeileshei/p/16955990.html

相关文章

  • ASP.NET常见错误 | 从客户端(.......)中检测到有潜在危险的 Request.QueryString 值
    由于在asp.net中,Request提交字段时出现有带特殊字符(&;-·)的字符串字段时时,程序系统会认为其具有潜在危险的值。环境配置会报出“从客户端(.......)中检测到有潜在危险的Requ......
  • range 实例(输出客户名和国家)
    TABLES:kna1.data:beginofgt_kna1occurs0,name1typekna1-name1,land1typekna1-land1,endofgt_kna1.DATA:rabTYPERANGEOFkna1-name1WIT......
  • 完整版在xcode打测试专用ipa包流程​
     前言:有时候,想要把自己的程序运行在别人的iphone手机上,但又不能通过本地真机调试的方法安装,这个时候我们就要打一个测试专用的ipa包给远方的测试小伙伴们测试。​ 步......
  • JS特殊语法 流程控制语句
    语局以;结尾如果一行只有一条语句则;可以省略(不建议)变量的定义使用var关键字也可以不使用用:定义的变量是局部变量不用:定义的变量是全局变量(不建议)  ......
  • ​最新Xcode9 无证书真机调试流程
     写在前面公司分配了新的测试机,证书99台名额已满,所以上网找教程,学习了一下如何使用Xcode无证书进行真机调试。​ 一.创建证书​1.运行Xcode,Xcode–》Preferen......
  • 上线流程
    上线流程上线前准备首先将跑在本地版本的项目,上传至远端(gitee、github上)重新复制一份项目的配置文件,可以命名为pro.py(dev为开发阶段的配置文件,pro为上线的配置文件)......
  • 客户端禁用Keep-alive, 服务端开启Keep-alive,谁是主动断开方?
    转自:https://www.cnblogs.com/JulianHuang/p/15870549.html 最近部署的web程序,在服务器上出现不少time_wait的连接状态,会占用tcp端口,费了几天时间排查。之前我有结论......
  • Android高仿网易新闻客户端之动态添加标签
    承接上一篇文章:​​Android高仿网易新闻客户端之首页​​,今天来实现动态添加标签效果。动态标签页是一个流式布局,实现了宽度自动换行高度自动分配的功能,代码如下:FlowLayout.......
  • Android高仿网易新闻客户端之首页
    关于实现网易新闻客户端的界面,以前写过很多博客,请参考:​​Android实现网易新闻客户端效果​​​​Android实现网易新闻客户端侧滑菜单(一)​​​​Android实现网易新闻客户端......
  • Android高仿网易新闻客户端之侧滑菜单
    承接上一篇文章:​​Android高仿网易新闻客户端之动态添加标签​​,今天实现侧滑菜单的效果。关于侧滑菜单,有很多种实现方式:1.自定义ViewGroup请参考:​​Android实现网易新......