В последнее время я работаю над функцией управления процессами в системе, по сравнению с основными дизайнерами процессов, многие из них приходится реализовывать в сочетании со скриптами. Для дизайнера полного стека, стремящегося к идеальному пользовательскому опыту, такой подход не должен работать. На самом деле нашей системе не обязательно иметь такой сложный опыт эксплуатации. После некоторых поисков я обнаружил, что процесс увольнения Диндин очень хорош.
Интерфейс простой и понятный, подходит для систем с фиксированными типами процессов. Поэтому я начал анализировать его, чтобы увидеть, как он управляет процессом, и связался с моей системой для переноса и оптимизации.
Анализ функционального дизайна
Дизайнер процессов 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 использует глобальную отправку, но также не делал этого).
Ведь проблему еще нужно решить, а вдруг пользователь получит такой процесс? Это очень просто.Когда новый процесс отправлен, если процесс является незаконным, он вернет пользователю «Существует проблема с дизайном процесса, пожалуйста, свяжитесь с соответствующим персоналом по дизайну процесса, чтобы изменить его!» и заблокировать подача процесса.
выполнить
посмотри структуру файла
|-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>
стиль фокуса
Коробочная модель выглядит так:
соединение с использованием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;
}
}
}
ОК Эта статья заканчивается~