ReactNative长流程交易管理引擎的设计与实现

ReactNative长流程交易管理引擎的设计与实现

实现原理

  1. 使用react-navigation对长流程每个节点的画面进行管理
  2. 每个流程建立独立的配置文件,用于控制整个交易的流程
  3. 通过统一入口开启流程
  4. 通过统一的流程管理工具控制流程中的画面跳转、数据流转等等
  5. 统一流程管理工具提供了画面出口管控、画面跳转、交易数据管理、开启/退出流程控制等等功能

实现过程

  1. 初始化工程
	react-native init rn-tradedemo
  1. 添加react-navigation、babel插件等相关依赖:
	npm i react-navigation@3.11.1 -S
	npm i react-native-gesture-handler -S
	npm i babel-plugin-root-plugin -D
  1. 配置babel.config.js,为特定路径命名
module.exports = {
  presets: ['module:metro-react-native-babel-preset'],
  plugins: [
    ["babel-plugin-root-import",
      {
        "paths": [
          {
            "rootPathPrefix": "$/",
            "rootPathSuffix": "./src/"
          }
        ]
      }
    ],
  ]
};
  1. 在/src/pages/demo1下创建长流程配置文件tradeflow.json
{
  "tradecode": "demo1",
  "pages": [
    {
      "title": "page1",
      "path": "$/pages/demo1/tradepages/page1",
      "componentName": "page1",
      "navigationOptions": {
        "header": null
      }
    },
    {
      "title": "page21",
      "path": "$/pages/demo1/tradepages/page2.1",
      "componentName": "page21",
      "navigationOptions": {
        "header": null
      }
    },
    {
      "title": "page22",
      "path": "$/pages/demo1/tradepages/page2.2",
      "componentName": "page22",
      "navigationOptions": {
        "header": null
      }
    },
    {
      "title": "page3",
      "path": "$/pages/demo1/tradepages/page3",
      "componentName": "page3",
      "navigationOptions": {
        "header": null
      }
    },
    {
      "title": "page4",
      "path": "$/pages/demo1/tradepages/page4",
      "componentName": "page4",
      "navigationOptions": {
        "header": null
      }
    },
    {
      "title": "page5",
      "path": "$/pages/demo1/tradepages/page5",
      "componentName": "page5",
      "navigationOptions": {
        "header": null
      }
    }
  ],
  "tradeflow": {
    "title": "page1",
    "default": {
      "title": "page21",
      "default": {
        "title": "page3",
        "default": {
          "title": "page5"
        }
      }
    },
    "other": {
      "title": "page22",
      "default": {
        "title": "page4",
        "default": {
          "title": "page5"
        }
      }
    }
  }
}
  1. 开发统一流程管理工具tradeflow
    5.1 统一流程管理工具用于流程的启动、退出、画面跳转、数据管理等功能
    5.2 统一流程管理工具提供的方法
方法名描述
getTradeCode获取流程代码
setTradeCode设置流程代码
setTradeFlow设置当前流程配置
nextStep根据传入的出口信息,跳转下一步
back回退上一步
exitTrade退出流程
setTradeData设置交易数据
getTradeData获取交易数据
getAllTradeData获取全部交易数据
removeTradeData删除交易数据
clearTradeData清空交易数据
startTrade开启流程

5.3 代码

/**
 * 交易流程控制
 * @author Lucifer
 */

// 设置交易流程的全局参数
// 交易码
if (!window.tradeCode) {
  window.tradeCode = null;
}

// 交易流程
if (!window.tradeFlow) {
  window.tradeFlow = null;
}

// 当前交易节点
if (!window.currentTradeStep) {
  window.currentTradeStep = [];
}

// 当前交易的数据
if (!window.currentTradeData) {
  window.currentTradeData = {};
}

/**
 * 获取下一个节点的名称
 * @author Lucifer
 */
function getBackStep(flow, step) {
  if (flow.title === step) {
    return flow;
  } else {
    for (let key in flow) {
      if (key !== "title" && key !== "back") {
        let backStep = getBackStep(flow[key], step);
        if (backStep) {
          return backStep;
        }
      }
    }
  }
}

function getCurrentTradeStep() {
  return window.currentTradeStep[window.currentTradeStep.length - 1];
}
function getCurrentTradeStepName() {
  return getCurrentTradeStep().title;
}

export default {
  /**
   * 获取当前的交易码
   * @author Lucifer
   */
  getTradeCode() {
    return window.tradeCode;
  },

  /**
   * 设置当前交易码
   * @author Lucifer
   * @param tradecode 交易码
   */
  setTradeCode(tradecode) {
    window.tradeCode = tradecode;
  },

  /**
   * 设置当前交易流程
   * @author Lucifer
   * @param tradeflow 当前交易流程
   */
  setTradeFlow(tradeflow) {
    window.tradeFlow = tradeflow;
    window.currentTradeStep.push(tradeflow);
  },

  /**
   * 进入交易的下一个节点
   * @author Lucifer
   * @param tradepage 当前交易页面对象
   * @param out 出口名称(可不传,默认为default)
   */
  nextStep(tradepage, out) {
    if (!out) {
      out = "default";
    }

    window.currentTradeStep.push(getCurrentTradeStep()[out]);
    const routerName = `${window.tradeCode}-${getCurrentTradeStepName()}`;

    tradepage.props.navigation.replace(routerName);
  },

  /**
   * 退回到交易的上一个节点
   * @author Lucifer
   * @param tradepage 当前交易页面对象
   */
  back(tradepage) {
    if (window.currentTradeStep.length > 0) {
      window.currentTradeStep.pop();
      const routerName = `${window.tradeCode}-${getCurrentTradeStepName()}`;

      tradepage.props.navigation.replace(routerName);
    }
  },

  /**
   * 退出当前交易
   * @author Lucifer
   * @param tradepage 当前交易页面对象
   */
  exitTrade(tradepage) {
    // 清空交易相关数据
    window.tradeCode = null;
    window.tradeFlow = null;
    window.currentTradeStep = null;

    tradepage.props.navigation.goBack();
  },

  /**
   * 设置交易数据
   * @author Lucifer
   * @param key 交易数据Key
   * @param value 交易数据Value
   */
  setTradeData(key, value) {
    if (!window.currentTradeData) {
      window.currentTradeData = {};
    }

    window.currentTradeData[key] = value;
  },

  /**
   * 获取交易数据
   * @author Lucifer
   * @param key 交易数据Key
   */
  getTradeData(key) {
    if (!window.currentTradeData) {
      window.currentTradeData = {};
    }

    return window.currentTradeData[key];
  },

  /**
   * 获取交易全部数据
   * @author Lucifer
   */
  getAllTradeData() {
    if (!window.currentTradeData) {
      window.currentTradeData = {};
    }

    return window.currentTradeData;
  },

  /**
   * 根据Key删除交易数据
   * @author Lucifer
   * @param key 交易数据Key
   */
  removeTradeData(key) {
    if (!window.currentTradeData) {
      window.currentTradeData = {};
    }

    delete window.currentTradeData[key];
  },

  /**
   * 清空交易数据
   * @author Lucifer
   */
  clearTradeData() {
    window.currentTradeData = {};
  },

  /**
   * 开始交易
   * @author Lucifer
   * @param tradepage 交易画面
   */
  startTrade(tradepage) {
    tradepage.props.navigation.replace(`${window.tradeCode}-${getCurrentTradeStepName()}`);
  }
}
  1. 开发合并脚本
    6.1 合并脚本的目的是将N个流程的配置文件合并到一个统一的配置文件中,方便工程加载
    6.2 代码
const fs = require("fs");
const path = require("path");
const process = require("process");
const chalk = require("chalk");
const glob = require("glob");

const basePath = path.resolve(__dirname, "../src");
const destPath = `${basePath}/router/tradeRouters.js`;

let tradeCodes = [];

// 生成目标文件的内容
let destContent = `module.exports = {`;

glob.sync(`${basePath}/pages/**/tradeflow.json`).forEach(filepath => {
  const fileContentStr = fs.readFileSync(filepath, { encoding: "UTF-8" });

  const configJson = JSON.parse(fileContentStr);

  const tradecode = configJson.tradecode;

  if (tradeCodes.indexOf(tradecode) !== -1) {
    console.log(chalk.red("交易码有重复,请调整后再试"));
    process.exit(-1);
  } else {
    tradeCodes.push(tradecode);
    destContent += `"${tradecode}": {"pages": [`;

    const pages = configJson.pages;

    pages.map(node => {
      destContent += `{"title": "${node.title}", "screen": require("${node.path}"), "componentName": "${node.componentName}", "navigationOptions": ${JSON.stringify(node.navigationOptions)}},`;
    });

    destContent += `],
  "tradeflow": ${JSON.stringify(configJson.tradeflow)}`

    destContent += `},`;
  }
});

destContent += `}`;

fs.writeFileSync(destPath, destContent, {encoding: "UTF-8"});

  1. 开发统一流程入口页面
    7.1 统一流程入口的作用是根据路由传参
import React, { Component } from "react";
import { StyleSheet, View, Text } from "react-native";

import tradeRouters from "$/router/tradeRouters";

import TradeUtil from "$/trade-control";

module.exports = class TradeTemplate extends Component {
  constructor(props) {
    super(props);

    // 交易码
    const tradecode = this.props.navigation.getParam("tradecode");
    TradeUtil.setTradeCode(tradecode);
    // 根据交易码找到交易对应的流程配置信息
    const currentTradeFlow = tradeRouters[tradecode];
    TradeUtil.setTradeFlow(currentTradeFlow.tradeflow);

    TradeUtil.startTrade(this);
  }
  render() {
    return <View />;
  }
}
  1. 路由
    8.1 使用react-navigation用于统一的路由管理
    8.2 除正常配置的路由外,还需要将流程配置文件中的路由提取出来添加到统一路由管理中
    8.3 代码
import {createStackNavigator} from 'react-navigation';

const tradeRouters = require('./tradeRouters');

// 根据交易路由生成对应的路由配置
function buildTradeRouters() {
  let retList = {};
  for (let trade in tradeRouters) {
    const config = tradeRouters[trade];
    const tradeSteps = config.pages;

    console.log(trade);
    tradeSteps.map((node, index) => {
      let currentTradeRoute = {};
      currentTradeRoute.screen = node.screen;
      currentTradeRoute.componentName = `${trade}-${node.componentName}`;
      currentTradeRoute.navigationOptions = node.navigationOptions
        ? node.navigationOptions
        : {header: null};

      retList[`${trade}-${node.componentName}`] = currentTradeRoute;
    });
  }

  return retList;
}

let routerList = Object.assign(
  {
    homepage: {
      screen: require('$/pages/home/homepage'),
      componentName: 'homepage',
      navigationOptions: {header: null},
    },
    tradetemplate: {
      screen: require('$/pages/templates/tradetemplate'),
      componentName: 'tradetemplate',
      navigationOptions: {header: null},
    },
  },
  buildTradeRouters(),
);

module.exports = createStackNavigator(routerList, {
  initialRouteName: 'homepage',
});

  1. 测试
    9.1 在主页面中添加跳转demo1流程的方法,测试交易流程的运转。

源码链接

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Lucifer.0408

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值