Recently in the process management function of the system, compared with the major process designers, many of them should be combined with scripts to achieve. As a full-stack designer looking for a perfect user experience, this is definitely not the way to go. In fact, there is no need for so complex operation experience for our system. Look for a time, found nail nail leave process experience is very good.

Simple and clear interface, suitable for fixed process type system. So I began to dissect him to see how he controlled the process, and contacted my system for transplantation and optimization.

Functional design analysis

The process designer divides the nodes of the approval process into three categories:

  • The examination and approval node
  • Conditional branch
  • cc

The approval types of “approval node” are as follows: designated member, director, role, sponsor’s choice, sponsor’s own, contact in the form, continuous multi-level director,… , and more subdivided property operations for these types.

Then the “condition branch” is greater than, equal to, less than, greater than or equal to some specified fields in the “leave” (this only leave process design)…… Then output multiple branches according to the judgment results, followed by the approval node.

“Cc” here in fact can be fused to any node inside, but the nail team chose to point out is also a good choice, operators understand more intuitive. My system is not im-based so cc is less important, but I did pull out the cc feature for comparison when I was doing user research, and a lot of users said it was great (they probably didn’t use email).

The process designer of Dingpin also makes fault tolerant judgments, such as whether the content of each node is complete and legal when publishing the process. That’s the problem, as we’ll get to later.

The UI implementation

Nail nail this process designer is implemented by DIV+CSS, it can be said that the man’s CSS skills are very good. I heard that Ali’s React technology is selected, so it should be a component recursion, and the data structure is similar to a tree structure, like the following:

But editing this is a little bit different than traditional tree editing. For example, when a user adds a node between two nodes, the parent of the lower node becomes the new node, and the child of the upper node becomes the new node.

Alternatively, the server can return an expanded tree like this:

{
    "1": {"name":"XXXX"
        "pid":"2"."type":"approver"... },"2": {"name":"XXXX"
        "pid":"1"."type":"approver"... }... }Copy the code

You can then write an operation constructor (regardless of DOM generation).

class TreeOperate {
    constructor(arguments){TODO}
    /* * id generation, do some processing according to the timestamp to generate a unique ID */
    generateId(){}
    /* * Combines the raw data into a tree structure, and each node operation performs a reorganization, that is, operates on the expanded tree data above, not the assembled tree data. * /
    compose(){}
    /* * Verify the validity of the process */
    werification(){}
    /* * Insert node, there are three types of node (branch, approval, copy) * also need to check whether the insert node has child node, if so, change the pid of child node to the current node ID */
    addNodes(){}
    /* * If the node has children, remove it first. Use addNodes() to add its children to its parent */
    removeNodes(){}
    /* * To modify a node, the process designer for pinning does not support dragging to change the parent node or modifying the node content, so modifying a node is only the content of the node to modify */
    editNodes(){}
}
Copy the code

disadvantages

Like nailing after completion of the editor to submit the overall data structure, then the weight of each node ID generated on the front-end developer’s shoulder, and that the presentation of data, the back-end must empty the existing process node analytical new data fill in the table again, to effort (if not cleared to delete, more troublesome, so also not too safe.

I was just thinking, why did Spike do that? There is no reason, although nail nail details of the things a lot, but not to do so, is it just for the overall check? ! If this is the case, it is a little strange that the following process passes the legal verification, as shown below:

Such an apparently illegal process was deemed legal. What if there was no approval, and the conditional branch just ended the process? @Dingding front-end Engineer

Localized improved version

Design ideas

After finding these shortcomings, my system uses VUE to write front-end. Let’s see the results:

Since there is no cc, there are only two node types: “approval node” and “conditional branch”. Take a look at the options for the approval node to see how I think about it:

The key to the

Click the save button to submit the node content directly to the server, the server will automatically reassemble the data structure back to me, then I just need to render again! The same goes for delete. I just pass the current node ID to the back end, and then the back end returns the deleted process node data to me and renders it again. Here’s a picture to compare these two methods:

The problem

This one operation, always big problem is can’t verify the legitimacy of the overall process, probably the user submitted a wrong process, therefore, lead to business process, but by comparing the positive and negative to use cases, found that worry is redundant, because there is only one mentioned above can not live without approval “after” the condition node of this kind of validity check, This validation-by-commit approach can handle all use cases (this validation is not done even though global commit is used).

The problem has to be solved eventually. What if the user creates such a process? Very simple, if the new process is not legal, the user will be sent a message “There is a problem with the process design, please contact the relevant personnel of the process design to modify!” And block the process submission.

implementation

Look at the file structure

|-workFlow.vue
|-node.vue
Copy the code

Using component recursive method, process tree rendering. Here’s a look at the node.vue code:

    <template>
    <div class="work-flow-item">
        <! -- Check if the process is a branch, if it is, loop the internal nodes of the branch -->
        <div v-if="data.type == 'branch'" class="work-flow-conditionNodes c-flex c-flex-center">...<Item v-for="item in data.conditionNodes" :type="type" :config="config" :key="item.id" :data="item"/>
        </div>
        <! -- item body start -->
        <div class="c-flex c-flex-center card-warp" v-if="data.type ! = 'end' && data.type ! = 'branch'">
            <el-card :class="data.type">
                <span slot="header">{{data.name}}</span>
                <! -- Check whether the process is conditional, if yes, render according to the condition -->
                <div v-if="data.type == 'condition'" class="sys-flow-content">
                    <font v-if="data.params && config[type]">{{config [type]. Long}} :</font>
                    <font v-if=! "" data.params">Other conditions enter this process</font>
                    <span v-for="(val,key) in data.condition" :key="key">
                         {{equation[key]}}{{val}}  
                    </span>
                </div>
                <div v-if="data.type == 'approver'" class="sys-flow-content">
                    <font v-if="approver[data.approver.type]">The approver:</font>
                    {{approver[data.approver.type]}} 
                    <span v-if="data.approver.name">{{data.approver.name}}</span>
                </div>
            </el-card>...</div>
        <! -- item end of body -->
        <! Determine if nextNode exists in the process, recurse if so, end if not -->
        <Item v-if="data.nextNode" :data="data.nextNode" :type="type" :config="config"/>        
    </div>
</template>
Copy the code

Style of emphasis

The box model is as follows:

Wiring uses before and after pseudo-classes, which have the advantage of flexible control.

Take a look at the following code:

.work-flow-item{ .el-card{ overflow: visible; position: relative; &::after{ content: ""; position: absolute; width: 2px; height: @height; background-color: @color; bottom: -@height; left: 99px; } &::before{ content: ""; position: absolute; width: 2px; height: @height; background-color: @color; top: -@height; left: 99px; } } .work-flow-conditionNodes{ background-color: #f5f6f8; &::after{ content: ""; position: absolute; width: calc(~"100% - 200px"); height: 2px; background-color: @color; bottom: 0; left:99px; } &>.work-flow-item{ position: relative; &::before{ content: ""; position: absolute; width: 2px; height: 100%; background-color: @color; top: 0; left:calc(~"50% - 1px"); } } &::before{ content: ""; position: absolute; width: calc(~'100% - 200px'); height: 2px; background-color: @color; top: 0; left: 99px; }}}Copy the code

OK End of this article ~