Record, play with each other in pain pondering, small thinking filled with life. There are very few articles about how to write business and why; Although the specific business is not commonly used, concrete examples or stories are also one of the ways to understand conceptual knowledge, and people will see different things from them.

background

Business scenario is the order list page, each order has a sub-order, sub-order has multiple status fields, there are about ten operations for the order, each operation has different requirements for data, an operation corresponds to an interface, the following is a simple processing method, maybe some help to you.

Train of thought

The first thing that came up was the idea of unifying the processes of these operations. Definitely not if-else switch case, take a cue from some articles that deal with a lot of if-else, link at the end. Unified processing flow, one entry function, one operation corresponds to one interface, collection of parameters of different interfaces, check whether the selected data meets the requirements of the operation, all these processes must be applicable to all interfaces.

In three steps, describe the interface (operation), define the filter rule, and define the function that performs the judgment

The desc.js file describes the information of each interface and provides some data for the page index.vue file to use.

Rule. Js defines the data requirements of each interface, which is used for rules configuration of the interface description in desc.js.

Hight. Js defines the loopRules function. Each selected data will execute the rules in interface rules to determine whether the data meets the current operation

Index. Vue Param holds parameter description objects for all operations. Key is the URL of the interface, value is param,actionStatus is the URL of the current operation, and the parameters of the current operation are stored in currentParam. The checkedList array holds the checked subdata, {child: {… }, the parent: {… }}, child is the child order, parent is the parent order

The code in the following file removes code that is not relevant to the process

Desc.js describes the interface

Operations one-to-one interface, where urls are unique identifiers (can be improved)

// desc.js
import { Rules } from './rules'
export const actionList = [
  {
    url: "checkOrder".title: "Review".desc: ""},...// Edit, cancel, lock, unlock...
export const checkOrder_api = {
  url: "checkOrder".title: "Review".method: "post".param: { / / parameters
    outSideCodes: [] // Take the selected data from the table. The array represents multiple choices and the field is named outSide
  },
  info: '1, check the invoice, you can choose more. The status of the invoice can only be "pending review" and the sub-order is not locked. The same invoice must be reviewed at the same time. '.rulesName: ["_isParentChecked"."_isParentStatusOne"."_noLockedChild"].// Data requirements for this operation
  rules: Rules.filter(item= > ["_isParentChecked"."_isParentStatusOne"."_noLockedChild"].includes(item.name)),
  tips: 'Confirmation box prompt'}; .// For ease of understanding, the interface description object has a value in the param, but needs to be empty;
export function collectApiParam(Desc) {
  let param = {};
  for (let item of actionList) {
    let item_api = actionToApi(item.url);
    param[item_api] = deepCloneWithoutValue(Desc[item_api].param, true);
  }
  return param;
}
{" chkorderS_API ": {"outstkCodes": []}, "cancorderS_API ": {"outstkCodes": [], "ids": []},... }
Copy the code

rules.js

export const Rules = [
  {
    name: "_isParentChecked".desc: "This operation only applies to all items under the same invoice number.".expression: ({ child, parent }) = > {
      // Return false hit
      let is = true;
      if(child.checked && ! parent.checked) {// The box is not automatically deselected
        // for (let item of parent.send_items) {
        // item.checked = false;
        // }
        // parent.checked = false;
        is = false;
      }
      return is;
    },
    message: (title) = > {
      return `${title}: Operation pins only for all goods under the same invoice number;
    },
    // The following three are the three configuration fields of the prompt box
    title: "".type: "".duration: 3000.// beforeNotify: () => {} Returns Boolean
    // beforeNotify, we can stop Notify by changing isCheck, so the process can keep on after rule
  },
  {
    name: "_isParentStatusOne".desc: "Only invoices to be audited, one sub-order to be audited, the entire invoice to be audited.".expression: ({ child, parent }, checkedList) = > {
      // Return false hit
      let is = false;
      for (let item of parent.send_items)
        if (item.outstkFlag === 1) {
          is = true;
        }
      return is;
    },
    message: (title) = > {
      return `${title}: Can only process invoices pending audit;
    },
    title: "".type: "".duration: 3000}, {name: "_noLockedChild".desc: "Is the shipping order locked?".expression: ({ child, parent }) = > {
      // Return false hit
      let is = true;
      console.log(" child.lockFlag", child.lockFlag);
      if (child.lockFlag === "T") {
        is = false;
        child.checked = false;
        parent.checked = false;
      }
      return is;
    },
    message: (title) = > {
      return `${title}: unable to execute, shipping order has locked ';
    },
    title: "".type: "".duration: 3000,},... ]Copy the code

High. Js loopRules function

import Vue from "vue";
const vue = new Vue();
// Each checked data handles a certain rule for an operation;
/** * The rule is executed for each item in the checkList *@param {*} Desc Indicates the interface description object *@param {*} Rule Indicates the rule * on the interface@param {*} CheckedList Already checked data */
function baseFun(desc, rule, checkedList) {
  let isCheck = true;
  for (let item of checkedList) {
    // True checkedList data format, each check list saves the parent {child: xx, parent: xx}
    if(! rule.expression(item, checkedList)) {// Deselect conflicting data
      isCheck = false; }}// beforeNotify, we can stop Notify by changing isCheck, so the process can keep on after rule
  if (rule.beforeNotify) {
    isCheck = rule.beforeNotify(isCheck, rule, desc);
  }
  if(! isCheck) { vue.$notify({title: rule.title ? rule.title : "Tip".message: rule.message(desc.title),
      type: rule.type ? rule.type : "warnning".duration: rule.duration ? rule.duration : 3000});console.log("notify");
    return false; // Exit the loopRules loop if the rule is hit;
  }
  return true;
}
/ * * * *@param {*} Desc The title and rules fields * are used in the interface description@param {*} CheckedList Checks data */
export function loopRules(desc, checkedList) {
  // debugger;
  for (let rule of desc.rules) {
    if(! baseFun(desc, rule, checkedList)) {// The matching rule stops the execution of subsequent rules
      return false; }}return true;
}
Copy the code

index.vue

The actionList in desc.js is used by the select component in the index.vue action bar. The this.param object in index.vue records the parameters of all interfaces. The _collectParam function collects the parameters of the current operation.

// index.vue Collect All operation parameter description objects,
import * as Desc from "./desc";
data() {
  return {
      tableData: [],
      Dec,
      actionList: Desc.actionList, // List of actions
      actionStatus: "".// The currently selected action item, namely the URL
      param: {}, // All interface parameters}},created() {
  this.initParam();
  this.getTableData();
},
methods: {
    handleAction() {
      // There is actionStatus and data, otherwise nothing can be done
      if (!this._needActionStatusAndData()) return;
      let desc = Desc[Desc.actionToApi(this.actionStatus)];
      // The hit rule is no longer followed
      if(! loopRules(desc,this.checkedList)) return; .this.submit();
    },
    // It just happens that the remarks fields of both interfaces are called lockMark
    // You can set the flag bit with remarks on the interface description object.
    submit() {
          let actionApi = Desc.actionToApi(this.actionStatus);
          let submitData = JSON.parse(JSON.stringify(this.currentParam));
          let { data, err } = await axiosApi(Desc[actionApi], submitData);
    },
    // Get list data
    async getTableData() {
      let { data, err } = await this.axiosApi(Desc.orderLists_api, this.queryPrdlists);
      this.tableData = data.data.data.data; // The data level is a bit off ba
      this.addProperyForTableDataItem(); 
    },
    // Initialize all interface parameters
    initParam() {
      this.param = Desc.collectApiParam(Desc);
    },
    changeActionStatus() {
      this._collectParam();
    },
    // Collect the parameters of the current interface
    _collectParam() {
      if (!this.actionStatus) return;

      this.initParam();
      let actionStatusApi = Desc.actionToApi(this.actionStatus);
      let currentParam = this.param[actionStatusApi]; CurrentParam = this.currentParam = this.currentParam = this.currentParam
      for (let { child, parent } of this.checkedList) {
        for (let key in currentParam) {
          let endOfS = Array.from(key).slice(-1) [0= = ="s" ? true : false;
          if(! child[key] && endOfS) {// outskCodes with child.outsktcode and stkCodes with child.stkcode
            // Select multiple fields as array type; // Select multiple fields as array type
            let keyWithoutS = Array.from(key)
              .slice(0, key.length - 1)
              .join("");
            if (child[keyWithoutS] && currentParam[key] && currentParam[key].constructor === Array) {
              currentParam[key].push(child[keyWithoutS]);
            } else if(! child[key] && child[keyWithoutS] && ! currentParam[key]) { currentParam[key] = child[keyWithoutS]; }}else {
            currentParam[key] = child[key] ? child[key] : undefined; }}}},},}Copy the code

The basic process consists of three steps: describe the interface (operation), define the filter rules, and define the function that performs the judgment. Essentially, if-else judgment is split, using “strategic mode” for logical judgment.

Horizontal expansion of the new operation, very convenient, just more in-depth expansion of the specific operation of the processing process, not sure whether it can withstand;

I know that there are a lot of interference information unrelated to technology in the business, which is like a running account and lacks depth. I can only extract a simple field as an example to explain

PS

Full version: The table data is two-tier, and most operations have pop-up input or remarks field input addresses

Points that can be improved:

  • Using a URL as a unique identifier is not a good idea, there are different operations using the same URL with different parameters,
  • In the implementationlopRulesFunction, each piece of data does not conform to the specific rules to record, can be recorded in thecheckedListOn,checkedListArrays hold checked subsingletons,Child: {{... }, the parent: {... }}, child is the child order, parent is the parent orderbaseFunFunction of theif (! rule.expression(item, checkedList)) {... }The internal records do not conform to the rulesrule

reference

  • A more elegant way to write complex JavaScript judgments

  • There is another article that goes deeper into the specific business, but I haven’t understood it yet. It involves state machines, deep business —- and explores the development and design of complex front-end business