Спросите разработчиков DingTalk Leave Process Designer: есть ли проблема с программированием?

Vue.js

В последнее время я работаю над функцией управления процессами в системе, по сравнению с основными дизайнерами процессов, многие из них приходится реализовывать в сочетании со скриптами. Для дизайнера полного стека, стремящегося к идеальному пользовательскому опыту, такой подход не должен работать. На самом деле нашей системе не обязательно иметь такой сложный опыт эксплуатации. После некоторых поисков я обнаружил, что процесс увольнения Диндин очень хорош.

Интерфейс простой и понятный, подходит для систем с фиксированными типами процессов. Поэтому я начал анализировать его, чтобы увидеть, как он управляет процессом, и связался с моей системой для переноса и оптимизации.

Анализ функционального дизайна

Дизайнер процессов DingTalk делит узлы процесса утверждения на три категории:

  • Узел утверждения
  • условная ветвь
  • копия

в"Узел утверждения«Типы утверждения делятся на: назначенные участники, супервайзеры, роли, инициаторы, самовыбранные, сами инициаторы, контакты в форме, непрерывные многоуровневые супервайзеры, ..., и более подразделенные атрибутивные операции этих типов.

Потом"условная ветвь” — это суждение о большем, равном, меньшем, большем или равном некоторым указанным полям в «Оставить» (это только дизайн процесса ухода), а затем вывод нескольких ветвей в соответствии с результатами оценки, за которыми следует узел утверждения.

"копия«На самом деле это может быть интегрировано в любой узел, но для команды DingTalk также было бы хорошим выбором разделить его, и оператор может понять его более интуитивно. Моя система не основана на IM, поэтому функция CC становится менее Да, но это правда, что, когда я проводил исследование пользователей, я вынул функцию CC DingTalk для сравнения пользователей, и многие пользователи сообщили, что эта функция очень хороша (возможно, они не использовали электронную почту).

Разработчик процессов Dingding также выносит отказоустойчивые суждения: например, при публикации процесса необходимо оценить, является ли содержимое каждого узла полным и законным. Вот в чем проблема, как мы обсудим позже.

Реализация пользовательского интерфейса

Дизайнер процессов Dingding использует метод DIV+CSS, можно сказать, что у этого чувака очень хорошие навыки работы с CSS. Я слышал, что Али выбрал технологию React, поэтому это должна быть рекурсия компонентов, а структура данных похожа на древовидную структуру, например следующую:

Есть много способов превратить эту древовидную структуру в форму процесса.

Но это редактирование немного отличается от традиционного редактирования древовидной структуры. Например, когда пользователь добавляет узел между двумя узлами, родительский узел ниже становится новым узлом, а подчиненный над ним также становится новым узлом.

Есть еще способ, то есть сервер возвращает развернутые данные дерева, вот так:

{
    "1":{
        "name":"XXXX"
        "pid":"2",
        "type":"approver"
        ……
    },
    "2":{
        "name":"XXXX"
        "pid":"1",
        "type":"approver"
        ……
    }
    ……
}

Затем вы можете написать конструктор операции (без учета генерации DOM), общую структуру и идеи дизайна можно увидеть ниже:

class TreeOperate {
    constructor(arguments){TODO}
    /*
     * id生成,根据时间戳做一些处理生成唯一id
     */
    generateId(){}
    /*
     * 将原始数据组合成树结构,每次对节点操作都要执行一次重组,也就是说操作的是上面的展开的树数据,而不是组装的树数据。
     */
    compose(){}
    /*
     * 校验流程的合法性
     */
    werification(){}
    /*
     * 插入节点,有三种节点类型(分支、审批、抄送)
     * 还需要判断插入节点是否存在子节点,如果存在则将子节点pid改为当前节点id
     */
    addNodes(){}
    /*
     * 移除节点,同样判断移除节点是否有子节点,有的话先将自己移除,在使用addNodes()将自己的子节点放到自己的父节点内
     */
    removeNodes(){}
    /*
     * 修改节点,钉钉的流程设计器不支持拖动改变父节点和节点内容修改,那么修改节点也仅仅是节点的内容进行修改
     */
    editNodes(){}
}

недостаток

Если вы отправите общую структуру данных после редактирования, как DingTalk, бремя генерации идентификаторов для каждого узла будет возложено на плечи разработчиков внешнего интерфейса, а серверный должен очистить существующие узлы процесса и повторно проанализировать новые. данные после такой подачи.Заполнение данных в таблицу кропотливо и трудозатратно (если она не опустошена, ее нужно заново удалять, что более хлопотно), что не очень безопасно.

Мне было интересно, почему Dingding сделал это? ? Это действительно не имеет смысла.Хотя в деталях Dingding есть много вещей, но делать это не обязательно.Это только для общей проверки? ! Если это так, то следующий процесс проходит проверку на легальность немного странно (см. следующий рисунок):

Такой явно незаконный процесс был признан законным. Представьте, что одобрения нет, и процесс завершится сразу после условной ветки, это? @Dingding ведущий инженер

Локализованная и улучшенная версия

Идеи дизайна

Обнаружив эти недостатки, система на моей стороне использует vue для написания интерфейса, и посмотрите на эффект реализации:

Поскольку CC нет, есть только два типа узлов: «Узел утверждения» и «Условная ветвь». Взгляните на параметры узла утверждения, чтобы понять, как я думаю:

Поскольку полномочия инициатора ограничены, нет необходимости ограничивать инициатора в процессе, подобном Dingding, поэтому, как показано на рисунке, если утверждающий выбран в качестве руководителя вышестоящего отдела, вам нужно только указать узел имя. . Сервер будет искать каждый уровень в соответствии с деревом (есть расписание процесса для записи хода процесса), и соответствующий утверждающий получит запрос на утверждение.После операции сервер установит соответствующее значение статуса и внешний интерфейс будет оценивать в соответствии со значением состояния. Из соображений безопасности сервер также будет выполнять проверку статуса и перехват URL-адресов.

вот и дело

Нажав здесь кнопку «Сохранить», вы напрямую отправите содержимое узла на сервер, а сервер автоматически соберет и вернет мне структуру данных, затем мне просто нужно снова отрендерить ее, и все в порядке! То же самое верно и для удаления, я просто передаю текущий идентификатор узла в бэкэнд, а затем бэкэнд возвращает мне данные удаленного узла процесса, а затем повторно рендерит их. Используйте картинку, чтобы сравнить два метода:

图层 4sss.png

вопрос

Самая большая проблема с этим методом один за другим заключается в том, что он не может проверить законность всего процесса. Весьма вероятно, что пользователь отправляет неправильный процесс и блокирует бизнес-процесс. Одна из вышеупомянутых проверок законности " условные узлы не могут быть одобрены без одобрения», этот метод проверки и отправки один за другим может обрабатывать все варианты использования (эта проверка легальности Dingding использует глобальную отправку, но также не делал этого).

Ведь проблему еще нужно решить, а вдруг пользователь получит такой процесс? Это очень просто.Когда новый процесс отправлен, если процесс является незаконным, он вернет пользователю «Существует проблема с дизайном процесса, пожалуйста, свяжитесь с соответствующим персоналом по дизайну процесса, чтобы изменить его!» и заблокировать подача процесса.

выполнить

посмотри структуру файла

|-workFlow.vue
|-node.vue

Используйте рекурсивный метод компонентов для визуализации дерева процессов. Давайте сосредоточимся на коде node.vue:

    <template>
    <div class="work-flow-item">
        <!-- 判断流程是否是分支,是的话循环分支内部节点 -->
        <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 主体开始 -->
        <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>
                <!-- 判断流程是否为条件,是的话按照条件渲染 -->
                <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">其他条件进入此流程</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]">审批人:</font>
                    {{approver[data.approver.type]}} 
                    <span v-if="data.approver.name">{{data.approver.name}}</span>
                </div>
            </el-card>
            ……
        </div>
        <!-- item 主体结束 -->
        <!-- 判断流程是否存在nextNode,如果有则去递归,没有就结束 -->
        <Item v-if="data.nextNode" :data="data.nextNode" :type="type" :config="config"/>        
    </div>
</template>

стиль фокуса

Коробочная модель выглядит так:

图层 4sss.png

соединение с использованиемbeforeа такжеafterПсевдокласс, преимущество гибкое управление.

Посмотрите на следующий фрагмент кода:

.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;
        }
    }
}

ОК Эта статья заканчивается~