<template>
  <div class="check-flow-index-bg">
    <el-tree v-loading="treeLoading"
             class="leftTree"
             ref="leftTree"
             :data="pageLeftTreeData"
             node-key="id"
             highlight-current
             default-expand-all
             :props="{children: 'children', label: 'name'}"
             @node-click="handleClickTreeNode" />
    <div v-if="currentBusinessCode"
         class="check-flow-page-right"
         v-loading="rightLoading">
      <div class="check-flow-page-title">
        <div class="check-flow-page-title-line" />
        {{ pageTitle }}
      </div>
      <div class="check-flow-page-save">
        <el-button type="primary"
                   size="mini"
                   @click="handleSave">
          保存
        </el-button>
        <el-button size="mini"
                   v-if="this.currentWorkFlowId"
                   @click="handleDelete">
          删除
        </el-button>
      </div>
      <div class="check-flow-page-content">
        <div ref="panel"
             class="check-flow-panel">
          <div class="check-flow-panel-title-bg"
               style="width: 320px;">
            <div style="    border: 1px solid #ccc;border-radius: 5px;width: 320px;">
              <div class="check-flow-panel-title-block">
                {{ currentBusinessTitle }}
              </div>
              <div style="padding:5px;">
                <el-checkbox-group v-model="checkList" @change="changed = true">
                  <el-checkbox :label="0">申请人和审批人重复时，自动通过审批
                    <el-tooltip placement="top">
                      <div slot="content">①当申请人为A,审批流程为A - B - C时，审批流程变为B - C;<br />②当申请人为B,审批流程为 A - B - C时，审批流程变为A - C; </div>
                      <i class="el-icon-info"
                         style="color:#f5a623"></i>
                    </el-tooltip>
                  </el-checkbox>
                  <el-checkbox :label="1">相邻两个审批人为同一人时，自动通过审批
                    <el-tooltip placement="top">
                      <div slot="content">当审批流程为A - A - B - C，选中后，审批流程变为 A - B - C。</div>
                      <i class="el-icon-info"
                         style="color:#f5a623"></i>
                    </el-tooltip>
                  </el-checkbox>
                </el-checkbox-group>
              </div>
            </div>
            <flow-Add :finalEnd="blocks.length === 0"
                      :disabled="blocks.filter(itm=>typeof itm.type === 'number').length > 0"
                      @handleAddCheckBranch="handleAddFirstBranch"
                      @handleAddCheckPerson="handleAddFirstPerson" />
          </div>
          <check-flow ref="checkFlowBg"
                      :blocks="blocks"
                      :parentBranchIndex="0"
                      @clickBlock="handleClickBlock" />
        </div>
      </div>
    </div>
    <div v-if="showSlide || showConditionSlide"
         class="check-flow-right-slide-block-bg" />
    <div class="check-flow-right-slide-block"
         :style="{right: showSlide?'0':'-400px'}">
      <div style=" overflow: auto;
    height: calc(100% - 120px);">
        <div class="check-flow-right-slide-block-title">
          <div class="check-flow-right-slide-block-title-text">
            <span class="check-flow-desc-label">描述：</span>
            <el-input class="check-flow-desc-input"
                      v-model="slideDesc"
                      @focus="showSlideDescError = false;"></el-input>
            <span v-if="showSlideDescError"
                  class="check-flow-desc-error">"描述"为必填项</span>
          </div>
        </div>
        <div class="check-flow-right-slide-block-title">
          <div class="check-flow-right-slide-block-title-text">
            <span style="margin-left:10px">监听：</span>
            <el-select style="margin-left:7px"
                       v-model="slideStepListenerId"
                       placeholder="请选择"
                       @change="listenerChange"
                       clearable>
              <el-option v-for="(option, index) in availableListeners"
                         :key="index"
                         :value="option.id"
                         :label="option.name"></el-option>
            </el-select>
          </div>
        </div>
        <div class="check-flow-right-slide-block-middle">
          <div class="check-flow-right-slide-block-middle-top">
            <el-radio v-model="slideWhichType"
                      :label="0"
                      @change="handleCheckPersonType">
              指定成员
            </el-radio>
            <el-radio v-model="slideWhichType"
                      :label="1"
                      @change="handleCheckPersonType">
              职务
            </el-radio>
          </div>
          <el-button type="primary"
                     size="small"
                     icon="el-icon-plus"
                     @click="handleSlideAddOrEditPersonOrPost">
            {{ slideWhichType === 0?(slideSelected.length === 0?'添加成员':'修改成员'):(slideSelected.length === 0?'添加职务':'修改职务') }}
          </el-button>
          <div v-if="slideSelected.length > 0"
               class="check-flow-right-slide-block-middle-selected">
            <el-tag v-for="itm in slideSelected"
                    :key="slideWhichType === 0 ? itm.staffId : itm.roleId"
                    size="small"
                    closable
                    @close="handleSlideSelectedDelete(itm)">
              {{ slideWhichType === 0 ? itm.staffName : itm.roleName }}
            </el-tag>
            <el-button type="text"
                       size="mini"
                       @click="slideSelected = []">
              清空
            </el-button>
          </div>
        </div>
        <div class="check-flow-right-slide-block-countersign">
          <el-radio-group v-model="slideCounterSign">
            <el-radio :label="0">普通节点</el-radio>
            <el-radio :label="1">多签节点</el-radio>
          </el-radio-group>
        </div>
        <div class="check-flow-right-slide-block-bottom"
             v-if="slideCounterSign === 1">
          <div class="check-flow-right-slide-block-bottom-title">
            多人审批时采用的审批方式
          </div>
          <div class="check-flow-right-slide-block-bottom-option">
            <el-radio v-model="slideMultiType"
                      :label="0">
              会签（须所有审批人同意）
            </el-radio>
            <el-radio v-model="slideMultiType"
                      :label="1">
              或签（一名审批人同意或拒绝即可）
            </el-radio>
          </div>
        </div>
        <div class="check-flow-right-slide-block-bottom"
             v-else>
          <el-card class="box-card">
            <div slot="header"
                 class="clearfix">
              <span>通用设置</span>
            </div>

            <h5>是否开启审批超时提醒</h5>
            <span style="padding-left: 20px;">
              <el-radio-group v-model="overdueFlag">
                <el-radio label="0">否</el-radio>
                <el-radio label="1">是</el-radio>
              </el-radio-group>
            </span>
            <h5>时间</h5>
            <el-row>
              <el-col :span="12">
                <el-input-number v-model="overdueTime"
                                 :min="0"
                                 :disabled="overdueFlag*1===0"
                                 :controls="false"
                                 :max="999"
                                 style="width:80%"></el-input-number>
              </el-col>
              <el-col :span="12">
                <el-select v-model="overdueTimeUnit"
                           :disabled="overdueFlag*1===0"
                           placeholder="请选择时间单位">
                  <el-option label="小时"
                             value="HOUR"></el-option>
                  <el-option label="天"
                             value="DAY"></el-option>
                </el-select>
              </el-col>
            </el-row>
            <p></p>
            <div class="check-flow-right-slide-block-bottom-title" v-if="isFinance">
              是否开启部门内部审核 <span style="padding-left: 20px;">
                <el-switch active-value="1"
                           inactive-value="0"
                           v-model="deptAuditEnabled"></el-switch>
              </span>
            </div>
          </el-card>
        </div>
      </div>
      <div class="check-flow-right-slide-block-action">
        <el-button @click="handleCancelSlide">
          取消
        </el-button>
        <el-button type="primary"
                   @click="handleSlideSave">
          保存
        </el-button>
      </div>
    </div>
    <div class="check-flow-right-slide-block"
         :style="{right: showConditionSlide?'0':'-400px'}">
      <div class="check-flow-right-slide-block-middle condition-block-middle">
        <el-button size="small"
                   type="primary"
                   @click="handleConditionAddButtonClick">新增条件</el-button>
        <el-select v-if="slideSelectedConditions.length > 1"
                   v-model="slideBranchLogicOperator"
                   placeholder="条件连接符">
          <el-option value="AND"
                     label="并且"></el-option>
          <el-option value="OR"
                     label="或"></el-option>
        </el-select>
        <div class="condition-block-middle-content">
          <div v-for="(condition, index) in slideSelectedConditions"
               :key="condition.id"
               class="condition-block-middle-content-block">
            <el-select v-model="condition.varName"
                       @change="e => handleSlideConditionChange(e, condition)">
              <el-option v-for="(option, idx) in availableConditions"
                         :key="idx"
                         :value="option.varName"
                         :label="option.name"></el-option>
            </el-select>
            <div class="condition-block-middle-content-value">
              <el-select v-model="condition.logicalSymbol"
                         placeholder="逻辑符号">
                <el-option v-for="(option, idx) in condition.operators"
                           :key="idx"
                           :label="option.label"
                           :value="option.value"></el-option>
              </el-select>
              <el-input v-if="condition.varType === 'value'"
                        class="condition-content-input"
                        v-model="condition.varValue"
                        placeholder="请输入条件值"></el-input>
              <el-select v-else
                         v-model="condition.varValue">
                <el-option v-for="(option, idx) in condition.options"
                           :key="idx"
                           :value="option.value"
                           :label="option.label"></el-option>
              </el-select>
            </div>
            <el-button icon="el-icon-delete"
                       class="condition-block-middle-content-delete"
                       size="small"
                       @click="handleConditionDelete(index)">删除该项</el-button>
            <div class="condition-block-middle-seperator"></div>
          </div>
        </div>
      </div>
      <div class="check-flow-right-slide-block-action">
        <el-button @click="handleCancelConditionSlide">
          取消
        </el-button>
        <el-button type="primary"
                   @click="handleConditionSlideSave">
          保存
        </el-button>
      </div>
    </div>

    <el-dialog :title="slideWhichType === 0?'选择人员':'选择职务'"
               :visible.sync="dialogVisible"
               :close-on-click-modal="false">
      <div class="dialog-content">
        <div class="dialog-left">
          <div class="dialog-part-title">选择</div>
          <el-input class="dialog-left-search"
                    placeholder="搜索"
                    prefix-icon="el-icon-search"
                    v-model="dialogTreeFilterText">
          </el-input>
          <el-tree class="dialog-left-tree"
                   v-loading="dialogTreeLoading"
                   :data="dialogTreeData"
                   ref="dialogLeftTree"
                   :filter-node-method="dialogTreeFilterMethod"
                   @node-click="handleClickDialogTreeLeafNode" />
        </div>
        <div class="dialog-selected-zone">
          <div class="dialog-part-title">已选</div>
          <div v-for="item in dialogSelected"
               :key="slideWhichType === 0 ? item.staffId : item.roleId"
               class="dialog-selected-item">
            {{ slideWhichType === 0 ? item.staffName : item.roleName }}
            <el-button type="text"
                       @click="handleDeleteDialogSelected(item)">删除</el-button>
          </div>
        </div>
      </div>
      <div slot="footer">
        <el-button @click="handleClickDialogCancel">取 消</el-button>
        <el-button type="primary"
                   @click="handleDialogSelectedDone">确 定</el-button>
      </div>
    </el-dialog>
  </div>
</template>
<script>
import checkFlow from './check-flow';
import flowAdd from './flow-add';
import { getTreeList } from '../../api/organization/tree';
import {
  getBusinessListFromServer,
  queryPersonsUnderDept,
  queryRolesUnderDept,
  queryAllRolesInCompany,
  createWorkFlowToServer,
  getWorkFlowDefinitionFromServer,
  queryWorkFlowInfo,
  changeWorkFlowToServer,
  removeLatestWorkflow
} from '../../api/check-flow';
import getCheckListIdFromBusinessCode from './checkListId';
import getListenerIdFromBusinessCode from './listenerId';
import allAvailableConditions from './conditions';
import allAvailableListeners from './stepListeners';
import { getUuid } from '../../utils'
import { cloneDeep } from 'lodash'

export default {
  components: {
    checkFlow,
    flowAdd,
  },
  data () {
    return {
      isFinance: false,
      changed: false,
      editing: false, // 当前如果有审核流，则为true，属于修改审核流；否则为false，是新增审核流
      rightLoading: false,
      dialogTreeLoading: false,
      pageTitle: '申请单',
      showSlide: false, // 审核节点右侧弹出框
      showConditionSlide: false, // 条件右侧弹出框
      showSlideDescError: false,
      dialogVisible: false,
      pageLeftTreeData: [],
      treeLoading: false,
      blocks: [],
      blocksClone: [],
      currentWorkFlowId: '',
      currentBusinessCode: '',
      currentBusinessTitle: '',
      currentEditingBlock: {},
      currentEditingBranchBlockIndex: 0,
      slideDesc: '', // 右侧弹出框顶部的描述
      slideWhichType: 0, // 0是指定人员，1是指定职务
      slideCounterSign: 0, // 0是普通节点，1是多实例节点
      slideMultiType: 0, // 0是会签，1是或签
      slideSelectedConditions: [],
      slideBranchLogicOperator: '',
      dialogTreeFilterText: '',
      slideSelected: [], // 已选择的人或职务列表
      dialogTreeData: [], // 对话框里左侧树数据
      originalDialogTreeData: [], // 对话框里左侧树部门级的数据
      dialogSelected: [],
      allPersons: [],
      allRoles: [],
      slideStepListeners: [],  // 右侧弹出框节点监听类
      slideStepListenerId: '',
      deptAuditEnabled: '0', // 是否开启部门内部审核
      overdueFlag: '0', // 是否开启超时提醒
      overdueTime: 0,
      overdueTimeUnit: 'HOUR',
      checkList: [],
      compId: localStorage.getItem('enterprise-front-companyId')
    };
  },
  watch: {
    dialogTreeFilterText (val) {
      this.$refs.dialogLeftTree.filter(val);
    }
  },
  computed: {
    availableConditions () {
      if (this.currentBusinessCode) {
        const ava = allAvailableConditions[this.currentBusinessCode];
        if (ava) {
          return ava;
        }
        return [];
      }
      return [];
    },
    availableListeners () {
      if (this.currentBusinessCode) {
        const ava = allAvailableListeners[this.currentBusinessCode];
        if (ava) {
          return ava;
        }
        return [];
      }
      return [];
    }
  },
  async created () {
    this.treeLoading = true;
    await this.getAllPersons();
    await this.getAllRoles();
    await this.getBusinessList();
    // await this.defaultChooseLeftTreeFirstLeaf();
    await this.getDialogDepartments();
  },
  methods: {
    listenerChange (value) {
      this.slideStepListeners = [];
      if (value && value != null && value.length > 0) {
        this.slideStepListeners.push({
          event: 'all',
          listenerId: value
        });
      }
    },
    /* 业务代码 */
    async getAllPersons () {
      this.rightLoading = true;
      const res = await queryPersonsUnderDept();
      this.allPersons = res.records;
    },
    async getAllRoles () {
      const res = await queryAllRolesInCompany({ compId: localStorage.getItem('enterprise-front-companyId') });
      this.allRoles = res[0].children;
    },
    async getDialogDepartments () {
      const res = await this.getCompanyDepartments();
      this.dialogTreeData = res;
      this.originalDialogTreeData = JSON.parse(JSON.stringify(res));
    },
    async getBusinessList () {
      this.pageLeftTreeData = await getBusinessListFromServer({ categoryCode: 'WORKFLOW' });
      this.treeLoading = false;
      console.log(this.pageLeftTreeData)
      if(this.pageLeftTreeData[0].children[0]){
      this.pageTitle = this.pageLeftTreeData[0].children[0].name
      }
    },
    async defaultChooseLeftTreeFirstLeaf () {
      // 默认选中第一个
      const first = this.deepFindFirst(this.pageLeftTreeData);
      if (first.id && this.$refs.leftTree) {
        this.$refs.leftTree.setCurrentKey(first.id)
        await this.treeClickMethod(first.code);
      }
    },
    async treeClickMethod (code) {
      this.blocks = []
      this.rightLoading = true;
      this.currentBusinessCode = code;
      this.isFinance = (code.indexOf('FINANCE') !== -1)
      const res = await getWorkFlowDefinitionFromServer({
        businessCode: code
      });
      if (res.length > 0) {
        const workflowDefinition = res.find(item => item.latest === 1); // 目前工作流定义取latest字段是1的
        this.currentWorkFlowId = workflowDefinition.id;
        const info = await queryWorkFlowInfo({
          workflowId: workflowDefinition.id
        })
        const branchSameNodeIds = [];
        this.convertStepsToBlocks(info.steps ? info.steps : [], this.blocks, branchSameNodeIds, 0, false, false);
        this.currentBusinessTitle = workflowDefinition.name || this.pageTitle;
        this.checkList = Array.from(new Set([workflowDefinition.creatorQuickAuditFlag * 1 ? 0 : '', workflowDefinition.skipAdjacentFlag * 1 ? 1 : '']))
        this.editing = true;
      } else {
        this.blocks = [];
        this.editing = false;
        this.currentBusinessTitle = '' || this.pageTitle;
      }
      this.blocksClone = cloneDeep(this.blocks)
      this.rightLoading = false;
    },
    async getCompanyDepartments () {
      if (!localStorage.getItem('enterprise-front-companyId')) {
        this.$message.error('没找到对应的公司ID');
        return;
      }
      const res = await getTreeList({
        compId: localStorage.getItem('enterprise-front-companyId')
      });
      return res[0].children;
    },
    async doSave () {
      const steps = [];
      this.convertBlocksToSteps(this.blocks, steps, false, [], 1);
      const params = {
        compId: this.compId,
        name: this.currentBusinessTitle,
        businessCode: this.currentBusinessCode,
        skipAdjacentFlag: this.checkList.indexOf(1) > -1 ? '1' : '0', //是否跳过相邻步骤
        creatorQuickAuditFlag: this.checkList.indexOf(0) > -1 ? '1' : '0', //是否初创人与审核人相同时跳过
        checklistId: getCheckListIdFromBusinessCode(this.currentBusinessCode),
        listeners: [{
          event: 'all',
          listenerId: getListenerIdFromBusinessCode(this.currentBusinessCode)
        }],
        steps
      };
      if (this.editing) {
        await changeWorkFlowToServer({ ...params, id: this.currentWorkFlowId });
      } else {
        await createWorkFlowToServer(params);
      }
      this.editing = true;
      this.treeClickMethod(this.currentBusinessCode);
      this.$message({
        type: 'success',
        message: !this.editing ? '创建工作流成功' : '修改工作流成功',
        showClose: true,
      });
      this.changed = false
    },
    /* 事件处理函数 */
    // 点击页面左侧树节点
    handleClickTreeNode (data, node) { // 先获取工作流定义，再拿定义的id去取工作流详情
      if (node.isLeaf && this.currentBusinessCode !== data.code) {
        if(this.blocksClone.length !== this.blocks.length){
          this.changed = true
        }
        if(this.changed){
          this.$confirm('审核流的修改未保存,是否切换?','提示',{
            confirmButtonText: '确认',
            cancelButtonText: '取消',
            type: 'warning'
          }).then(() => {
            this.treeClickMethod(data.code);
            this.pageTitle = data.name
            this.changed = false
          })
        } else {
          this.treeClickMethod(data.code);
          this.pageTitle = data.name
          this.changed = false
        }
      }
    },
    // 添加第一个审核人节点
    handleAddFirstPerson () {
      const element = {
        id: getUuid(),
        type: 0,
        desc: '',
        deptAuditEnabled: 0,
        overdueFlag: 0,
        overdueTime: 0,
        overdueTimeUnit: 'HOUR',
        stepType: 'NORMAL',
        content: '',
        onBranch: false,
      };
      this.blocks.unshift(element);
    },
    // 添加第一个分支节点
    handleAddFirstBranch () {
      const element = {
        id: getUuid(),
        type: 1,
        onBranch: false,
        subBlocks: [
          {
            id: getUuid(),
            showDeleteBtn: false,
            blocks: [
              {
                id: getUuid(),
                type: 2,
                desc: '',
                deptAuditEnabled: 0,
                overdueFlag: 0,
                overdueTime: 0,
                overdueTimeUnit: 'HOUR',
                content: '',
                onBranch: true,
              },
            ],
          },
          {
            id: getUuid(),
            showDeleteBtn: false,
            blocks: [
              {
                id: getUuid(),
                type: 2,
                desc: '',
                deptAuditEnabled: 0,
                overdueFlag: 0,
                overdueTime: 0,
                overdueTimeUnit: 'HOUR',
                content: '',
                onBranch: true,
              },
            ],
          },
        ],
      };
      this.blocks.unshift(element);
    },
    // 点击审核流节点
    handleClickBlock (block, index) {
      if (block.type === 0) {
        this.showSlide = true;
        this.currentEditingBlock = block;
        // 以下都是赋初值
        this.slideDesc = block.desc;
        this.slideStepListeners = block.listeners;
        this.deptAuditEnabled = block.deptAuditEnabled + '';
        this.overdueFlag = block.overdueFlag ? block.overdueFlag * 1 + '' : '0'
        this.overdueTime = block.overdueTime ? block.overdueTime + '' : null
        this.overdueTimeUnit = (block.overdueTimeUnit) || null
        if (this.slideStepListeners && this.slideStepListeners.length > 0) {
          this.slideStepListenerId = this.slideStepListeners[0].listenerId;
        }
        this.slideCounterSign = block.stepType === 'NORMAL' ? 0 : 1;
        if (block.countersignType) {
          this.slideMultiType = block.countersignType === 'ALL' ? 0 : 1;
        } else {
          this.slideMultiType = 0;
        }
        // this.deptAuditEnabled = block.deptAuditEnabled + '';
        // this.overdueFlag = block.overdueFlag * 1 + ''
        // this.overdueTime = block.overdueTime + ''
        // this.overdueTimeUnit = (block.overdueTimeUnit) || ''
        // 审核流节点的指定人或者职务
        if (block.auditUsers) {
          // this.deptAuditEnabled = block.deptAuditEnabled + '';
          // this.overdueFlag = block.overdueFlag * 1 + ''
          // this.overdueTime = block.overdueTime + ''
          // this.overdueTimeUnit = (block.overdueTimeUnit) || ''
          this.slideWhichType = 0;
          const slideSelectedIds = block.auditUsers.split(',')
          slideSelectedIds.forEach((item) => {
            const slideItem = this.allPersons.find(itm => itm.staffId === item);
            if (slideItem) {
              this.slideSelected.push(slideItem)
            }
          })
        } else if (block.auditRoles) {
          this.slideWhichType = 1;
          const slideSelectedIds = block.auditRoles.split(',')
          slideSelectedIds.forEach((item) => {
            const slideItem = this.allRoles.find(itm => itm.roleId === item);
            if (slideItem) {
              this.slideSelected.push(slideItem)
            }
          })
        }
      } else if (block.type === 2) {
        this.showConditionSlide = true;
        this.currentEditingBlock = block;
        this.currentEditingBranchBlockIndex = index;
        this.slideSelectedConditions = block.branchConditions || [];
        this.slideBranchLogicOperator = block.branchLogicOperator;
      }
    },
    handleCancelConditionSlide () {
      this.showConditionSlide = false;
      this.cleanSlideConditionContent();
    },
    handleSlideConditionChange (value, condition) {
      const selectedCondition = this.availableConditions.find(itm => itm.varName === value);
      condition.varValue = '';
      condition.logicalSymbol = '';
      condition.operators = selectedCondition.operators;
      condition.varType = selectedCondition.varType;
      condition.options = selectedCondition.options;
      condition.name = selectedCondition.name;
    },
    handleConditionAddButtonClick () {

      this.$set(this.slideSelectedConditions, this.slideSelectedConditions.length, {
        id: getUuid(),
        name: '',
        varName: '',
        varValue: '',
        operators: [],
        varType: 'enum',
        options: [],
        logicalSymbol: ''
      })
    },
    handleConditionDelete (index) {
      this.slideSelectedConditions.splice(index, 1);
    },
    // 侧弹出框点击取消
    handleCancelSlide () {
      this.showSlide = false;
      this.cleanSlideContent();
    },
    // 点击侧弹出框删除已选
    handleSlideSelectedDelete (selectedItem) {
      if (this.slideWhichType === 0) {
        const idx = this.slideSelected.findIndex(item => item.staffId === selectedItem.staffId);
        this.slideSelected.splice(idx, 1);
      } else {
        const idx = this.slideSelected.findIndex(item => item.roleId === selectedItem.roleId);
        this.slideSelected.splice(idx, 1);
      }
    },
    // 点击对话框保存按钮
    handleDialogSelectedDone () {
      this.slideSelected = JSON.parse(JSON.stringify(this.dialogSelected));
      this.dialogVisible = false;
      this.dialogTreeFilterText = '';
    },
    // 对话框点击取消
    handleClickDialogCancel () {
      this.dialogVisible = false;
      this.dialogTreeFilterText = '';
    },
    // 转换指定人员或者职务
    handleCheckPersonType () {
      this.slideSelected = [];
      this.dialogTreeData = JSON.parse(JSON.stringify(this.originalDialogTreeData));
    },
    // 对话框搜索框过滤方法
    dialogTreeFilterMethod (value, data) {
      if (!value) return true;
      return data.label.indexOf(value) !== -1
    },
    // 点击对话框叶子节点
    async handleClickDialogTreeLeafNode (data) {
      if (this.slideWhichType === 0) { // 指定成员
        if (!data.children) { // 这个是选择某个人或职务
          if (!this.dialogSelected.some(item => item.staffId === data.staffId)) {
            this.dialogSelected.push(data);
          }
        } else if (data.children.length === 0) { // 这是部门最后一层
          this.dialogTreeLoading = true;
          const res = await queryPersonsUnderDept({ deptId: data.id });
          this.dialogTreeLoading = false;
          const children = res.records.map((item) => {
            return {
              ...item,
              label: item.staffName,
            }
          })
          data.children = children;
        }
      } else { // 选择职务
        if (!data.children) { // 这个是选择某个人或职务
          if (!this.dialogSelected.some(item => item.roleId === data.roleId)) {
            this.dialogSelected.push(data);
          }
        } else if (data.children.length === 0) { // 这是部门最后一层
          this.dialogTreeLoading = true;
          const res = await queryRolesUnderDept({ deptId: data.id });
          this.dialogTreeLoading = false;
          const children = res.records.map((item) => {
            return {
              ...item,
              label: item.roleName,
            }
          })
          data.children = children;
        }
      }
    },
    // 对话框点击删除已选
    handleDeleteDialogSelected (selectedItem) {
      if (this.slideWhichType === 0) {
        const idx = this.dialogSelected.findIndex(item => item.staffId === selectedItem.staffId);
        this.dialogSelected.splice(idx, 1);
      } else {
        const idx = this.dialogSelected.findIndex(item => item.roleId === selectedItem.roleId);
        this.dialogSelected.splice(idx, 1);
      }
    },
    // 侧审核节点弹出框点击保存
    handleSlideSave () {
      this.changed = true
      if (!this.slideDesc) {
        this.showSlideDescError = true;
        return;
      }
      this.currentEditingBlock.desc = this.slideDesc;
      this.currentEditingBlock.listeners = this.slideStepListeners;
      this.currentEditingBlock.stepType = this.slideCounterSign === 0 ? 'NORMAL' : 'COUNTERSIGN';
      if (this.slideCounterSign === 1) {
        if (this.slideMultiType === 0) {
          this.currentEditingBlock.countersignType = 'ALL';
        } else {
          this.currentEditingBlock.countersignType = 'ONE';
        }
        this.currentEditingBlock.deptAuditEnabled = 0;
        this.currentEditingBlock.overdueFlag = 0
        this.currentEditingBlock.overdueTime = 0
        this.currentEditingBlock.overdueTimeUnit = 'HOUR'
      } else {
        this.currentEditingBlock.deptAuditEnabled = this.deptAuditEnabled;
        this.currentEditingBlock.overdueFlag = this.overdueFlag || '0'
        this.currentEditingBlock.overdueTime = this.overdueTime || null
        this.currentEditingBlock.overdueTimeUnit = this.overdueTimeUnit || null
      }
      if (this.slideWhichType === 0) {
        const audits = this.slideSelected.map(item => item.staffId);
        const content = this.slideSelected.map(item => item.staffName).join()
        this.currentEditingBlock.auditUsers = audits.join();
        this.currentEditingBlock.auditRoles = null;
        this.currentEditingBlock.content = content;
      } else {
        const audits = this.slideSelected.map(item => item.roleId);
        const content = this.slideSelected.map(item => item.roleName).join()
        this.currentEditingBlock.auditRoles = audits.join();
        this.currentEditingBlock.auditUsers = null;
        this.currentEditingBlock.content = content;
      }
      this.showSlide = false;
      this.cleanSlideContent();
    },
    handleConditionSlideSave () {
      if (this.slideSelectedConditions.length > 1 && !this.slideBranchLogicOperator) {
        this.$message({
          message: '条件多于两个时，条件连接符不能为空',
          showClose: true,
          type: 'error'
        })
        return;
      }
      this.currentEditingBlock.stepType = 'CONDITION';
      const branchConditions = [];
      let branchContent = '';
      for (let index = 0; index < this.slideSelectedConditions.length; index++) {
        const item = this.slideSelectedConditions[index];
        if (item.varName && item.varValue && item.logicalSymbol) {
          branchConditions.push({
            name: item.name,
            varName: item.varName,
            varValue: item.varValue,
            logicalSymbol: item.logicalSymbol,
            options: item.options,
            operators: item.operators
          })
        } else if (!item.varName) {
          this.$message({
            message: '条件名不能为空',
            showClose: true,
            type: 'error'
          })
          return;
        } else if (!item.varValue) {
          this.$message({
            message: '条件值不能为空',
            showClose: true,
            type: 'error'
          })
          return;
        } else {
          this.$message({
            message: '条件逻辑符不能为空',
            showClose: true,
            type: 'error'
          })
          return;
        }
        const condition = this.availableConditions.find(itm => itm.varName === item.varName);
        const type = condition.varType;
        if (type === 'enum') {
          const operator = condition.operators.find(itm => itm.value === item.logicalSymbol).label;
          const value = condition.options.find(itm => itm.value === item.varValue).label;
          branchContent += (index + 1) + '. ' + condition.name + ' ' + operator + ' ' + value;
          if (condition.unit) {
            branchContent += ' ' + condition.unit;
          }
        } else {
          const operator = condition.operators.find(itm => itm.value === item.logicalSymbol).label;
          const value = item.varValue;
          branchContent += (index + 1) + '. ' + condition.name + ' ' + operator + ' ' + value;
          if (condition.unit) {
            branchContent += ' ' + condition.unit;
          }
        }
        if (index < this.slideSelectedConditions.length - 1) {
          branchContent += '<br />'
        }
      }
      if (branchConditions.length > 1) {
        this.currentEditingBlock.desc = '条件' + (this.currentEditingBranchBlockIndex + 1) + '  条件连接符:' + (this.slideBranchLogicOperator === 'AND' ? '并且' : '或');
      } else {
        this.currentEditingBlock.desc = '条件' + (this.currentEditingBranchBlockIndex + 1);
      }
      this.currentEditingBlock.branchConditions = branchConditions;
      this.currentEditingBlock.content = branchContent;
      this.currentEditingBlock.branchLogicOperator = this.slideBranchLogicOperator;
      this.showConditionSlide = false;
      this.cleanSlideConditionContent();
    },
    /**
     * 删除审核流
     * */
    async handleDelete () {
      // /workflow/api/removeLatestWorkflow
      await removeLatestWorkflow({ id: this.currentWorkFlowId }).then(() => {
        this.treeClickMethod(this.currentBusinessCode)
        this.$message({
          message: '删除工作流成功~',
          type: 'success'
        })
        window.location.reload()
      })
    },
    // 创建或修改审核流
    handleSave () {
      if (this.deepFindInvalidNode(this.blocks)) {
        this.rightLoading = true;
        this.doSave()
      } else {
        this.$message({
          type: 'error',
          message: '节点的描述和审核人(或审核职务)不能为空',
          showClose: true
        })
      }
    },
    // 弹出对话框
    async handleSlideAddOrEditPersonOrPost () {
      this.dialogSelected = JSON.parse(JSON.stringify(this.slideSelected));
      this.dialogVisible = true;
    },
    /* helper 函数 */
    cleanSlideContent () {
      this.slideSelected = [];
      this.slideWhichType = 0;
      this.slideCounterSign = 0;
      this.slideMultiType = 0;
      this.deptAuditEnabled = '0';
      this.overdueFlag = '0'
      this.overdueTime = '0'
      this.overdueTimeUnit = "HOUR"
      this.showSlideDescError = false;
      this.slideDesc = '';
      this.slideStepListeners = [];
      this.slideStepListenerId = '';
    },
    cleanSlideConditionContent () {
      this.slideBranchLogicOperator = '';
    },
    convertAudit (step) {
      let content = ''
      if (step.auditUsers) {
        const auditIds = step.auditUsers.split(',');
        const auditNames = [];
        auditIds.forEach((item) => {
          const audit = this.allPersons.find(itm => itm.staffId === item);
          // 有可能审核流里保存的人，已经被删除了，也就是说这个人已经从公司所有的人名单里删除了，下面职务亦然
          if (audit) {
            auditNames.push(audit.staffName);
          }
        })
        content = auditNames.join();
      } else if (step.auditRoles) {
        const auditIds = step.auditRoles.split(',');
        const auditNames = [];
        auditIds.forEach((item) => {
          const audit = this.allRoles.find(itm => itm.roleId === item);
          if (audit) {
            auditNames.push(audit.roleName);
          }
        })
        content = auditNames.join();
      }
      return content;
    },
    convertStepsToBlocks (steps, blocks, branchSameNodeIds, fromIndex, onBranch, shouldAddEndPoint) {
      let index = fromIndex;
      let whichBranch = 0;
      let subBlocks = [];
      let _shouldAddEndPoint = shouldAddEndPoint;
      let obj = {}; // 临时数据
      while (index < steps.length) {
        const item = steps[index];
        switch (item.stepType) {
          case 'NORMAL':
            if (item.branchNodeLocation !== 'END') { // 普通节点直接加上
              blocks.push({
                ...item,
                type: 0,
                content: this.convertAudit(item),
                onBranch,
              })
            } else { // END节点，需要在合适时机给加到主分支节点下面
              let endPoint = '';
              // END节点
              if (branchSameNodeIds.every(itm => itm !== item.branchSameNodeId)) {
                branchSameNodeIds.push(item.branchSameNodeId);
              }
              if ((item.auditUsers || item.auditRoles) && _shouldAddEndPoint) {
                endPoint = {
                  ...item,
                  type: 0,
                  content: this.convertAudit(item),
                }
              }
              return {
                index,
                endPoint
              };
            }
            break;
          case 'COUNTERSIGN':
            blocks.push({
              ...item,
              type: 0,
              content: this.convertAudit(item),
              onBranch,
            })
            break;
          case 'CONDITION':
            if (branchSameNodeIds.every(itm => itm !== item.branchSameNodeId)) { // 新的条件主节点
              // branchConditions
              const res = this.convertConditions(item.branchConditions);
              const branchConditions = res.branchConditions;
              const branchContent = res.branchContent;
              const conditionPoint = {
                id: item.id,
                type: 2,
                desc: '条件1  条件连接符:' + (item.branchLogicOperator === 'AND' ? '并且' : '或'),
                content: branchContent,
                branchConditions,
                branchLogicOperator: item.branchLogicOperator,
                onBranch: true
              }
              subBlocks = [{
                blocks: [conditionPoint],
                id: getUuid(),
                showDeleteBtn: false
              }];
              if (item.auditUsers || item.auditRoles) { // 这是个placeholder和实际节点的合并点，需要把它拆开
                let stepType;
                if (item.countersignType) {
                  stepType = 'COUNTERSIGN'
                } else {
                  stepType = 'NORMAL';
                }
                const beginPoint = {
                  ...item,
                  stepType,
                  type: 0,
                  content: this.convertAudit(item)
                }
                blocks.push(beginPoint);
              }
              branchSameNodeIds.push(item.branchSameNodeId);
              whichBranch = 0;
              blocks.push({
                id: getUuid(),
                type: 1,
                onBranch,
                subBlocks,
              })
              _shouldAddEndPoint = true;
            } else { // 新的条件子节点
              // branchConditions
              const res = this.convertConditions(item.branchConditions);
              const branchConditions = res.branchConditions;
              const branchContent = res.branchContent;
              const conditionPoint = {
                id: getUuid(),
                type: 2,
                desc: '条件' + (subBlocks.length + 1) + '  条件连接符:' + (item.branchLogicOperator === 'AND' ? '并且' : '或'),
                content: branchContent,
                branchConditions,
                branchLogicOperator: item.branchLogicOperator,
                onBranch: true
              }
              subBlocks.push({
                blocks: [conditionPoint],
                id: getUuid(),
                showDeleteBtn: false
              });
              whichBranch += 1;
              _shouldAddEndPoint = false;
            }
            obj = this.convertStepsToBlocks(steps, subBlocks[whichBranch].blocks, branchSameNodeIds, index + 1, true, _shouldAddEndPoint); // 继续深入遍历
            index = obj.index;
            if (obj.endPoint) {
              blocks.push(obj.endPoint);
            }
            break;
          default:
            break;
        }
        index++;
      }
    },
    convertConditions (conditions) {
      let branchContent = '';
      const branchConditions = [];
      for (let index = 0; index < conditions.length; index++) {
        const element = conditions[index];
        const condition = this.availableConditions.find(itm => itm.varName === element.varName);
        const type = condition.varType;
        if (type === 'enum') {
          console.log(condition.options,condition.options.find(itm => itm.value === element.varValue))
          const operator = condition.operators.find(itm => itm.value === element.logicalSymbol).label;
          const value = condition.options.find(itm => itm.value === element.varValue).label;
          branchContent += (index + 1) + '. ' + condition.name + ' ' + operator + ' ' + value;
          if (condition.unit) {
            branchContent += ' ' + condition.unit;
          }
        } else {
          const operator = condition.operators.find(itm => itm.value === element.logicalSymbol).label;
          const value = element.varValue;
          branchContent += (index + 1) + '. ' + condition.name + ' ' + operator + ' ' + value;
          if (condition.unit) {
            branchContent += ' ' + condition.unit;
          }
        }
        if (index < conditions.length - 1) {
          branchContent += '<br />';
        }
        branchConditions.push({
          varName: element.varName,
          varValue: element.varValue,
          logicalSymbol: element.logicalSymbol,
          name: condition.name,
          operators: condition.operators,
          varType: condition.varType,
          options: condition.options,
        });
      }
      return {
        branchContent,
        branchConditions
      }
    },
    deepFindFirst (list) {
      if (Array.isArray(list) && list.length > 0) {
        const item = list[0];
        if (Array.isArray(item.children) && item.children.length > 0) {
          return this.deepFindFirst(item.children);
        }
        return item;
      }
      return '';
    },
    deepFindInvalidNode (blocks) {
      for (let index = 0; index < blocks.length; index++) {
        const itm = blocks[index];
        if (itm.type === 0) {
          if (!itm.desc || !itm.stepType || !(itm.auditUsers || itm.auditRoles)) {
            return false;
          }
        } else if (itm.type === 1) {
          for (let idx = 0; idx < itm.subBlocks; idx++) {
            const element = itm.subBlocks[idx];
            const res = this.deepFindInvalidNode(element.blocks);
            if (!res) {
              return false;
            }
          }
        } else {
          if (!itm.desc || !itm.stepType) {
            return false;
          }
        }
      }
      return true;
    },
    makeEnd (nodeIds, index, blocks, level) {
      // 取到end节点的beginNodeId，并把开始和end节点都加入全局nodeIds数组中
      let branchBeginNodeId = 0;
      while (nodeIds.indexOf(branchBeginNodeId) !== -1) {
        branchBeginNodeId += 1;
      }
      const branchEndNodeId = branchBeginNodeId + 1;
      nodeIds.push(branchBeginNodeId);
      nodeIds.push(branchEndNodeId);
      // 取end节点
      if (index < blocks.length - 1) { // 当前非最后一个
        let nextIndex = index + 1;
        const temp = blocks[nextIndex];
        if (temp.type === 0) { // end节点是一个实际节点
          nodeIds.push(nextIndex + '_index_' + level);
          return {
            end: {
              desc: temp.desc,
              stepType: temp.stepType,
              auditUsers: temp.auditUsers,
              auditRoles: temp.auditRoles,
              branchNodeLocation: 'END',
              branchSameNodeId: branchEndNodeId + '',
              countersignType: temp.countersignType,
              listeners: temp.listeners
            },
            beginNodeId: branchBeginNodeId
          }
        }
      }
      return {
        end: {
          desc: '_PLACEHOLDER_',
          stepType: 'NORMAL',
          branchSameNodeId: branchEndNodeId + '',
          branchNodeLocation: 'END'
        },
        beginNodeId: branchBeginNodeId
      }
    },
    convertBlocksToSteps (blocks, res, onBranch, nodeIds, level, endPoint, beginPoint, beginNodeId) {
      for (let index = 0; index < blocks.length; index++) {
        const element = blocks[index];
        if (element.type === 0) { // 实际节点
          if (element.branchSameNodeId && element.branchSameNodeId != null && element.branchSameNodeId.length > 0) {
            continue;
          }
          if (nodeIds.indexOf(index + '_index_' + level) != -1) {
            continue;
          }
          if (index < blocks.length - 1 && blocks[index + 1].type === 1) {
            continue;
          }
          const item = {};
          item.desc = element.desc;
          item.deptAuditEnabled = element.deptAuditEnabled;
          item.overdueFlag = element.overdueFlag || '0'
          item.overdueTime = element.overdueTime ? element.overdueTime + '' : null
          item.overdueTimeUnit = element.overdueTimeUnit || null
          item.stepType = element.stepType;
          if (element.countersignType) {
            item.countersignType = element.countersignType;
          }
          if (element.auditUsers) {
            item.auditUsers = element.auditUsers;
          } else if (element.auditRoles) {
            item.auditRoles = element.auditRoles;
          }
          item.listeners = element.listeners;
          res.push(item);
        } else if (element.type === 1) {
          // 分支节点：取当前主分支下一个点(如果有)为branch end节点
          const result = this.makeEnd(nodeIds, index, blocks, level);
          const end = result.end;
          const beginNodeId = result.beginNodeId;
          // 取当前主分支上面的这个节点（如果有）为各个分支的branch begin 节点，并删除这个主分支上面的这个节点
          let begin;
          if (index > 0) {
            const last = blocks[index - 1];
            if (last.type === 0) {
              begin = last;
            }
          }
          level++;
          // 遍历子节点
          for (let idx = 0; idx < element.subBlocks.length; idx++) {
            const item = element.subBlocks[idx];
            this.convertBlocksToSteps(item.blocks, res, true, nodeIds, level, end, begin, beginNodeId);
          }
          level--;
        } else { // 条件框节点，需要合二为一（beginPoint是一，条件框节点是二，合二为一）
          const item = {};
          item.stepType = 'CONDITION';
          item.branchNodeLocation = 'BEGIN';
          item.branchSameNodeId = beginNodeId + '';
          const branchConditions = [];
          if (element.branchConditions && element.branchConditions.length > 0) {
            for (let index = 0; index < element.branchConditions.length; index++) {
              const item = element.branchConditions[index];
              branchConditions.push({
                varName: item.varName,
                varValue: item.varValue,
                name: item.name,
                logicalSymbol: item.logicalSymbol
              })
            }
          }
          item.branchConditions = branchConditions;
          item.branchLogicOperator = element.branchLogicOperator;
          // 如果上层有beginPoint，需要把原来convertStepsToBlocks时拆开的点合起来，这个beginPoint
          if (beginPoint) {
            res.push({
              ...beginPoint,
              ...item
            });
          } else {
            res.push({
              ...item,
              desc: '_PLACEHOLDER_'
            });
          }
        }
        if (index === blocks.length - 1 && onBranch) {
          res.push(endPoint);
        }
      }
    },
  },
};
</script>
<style lang="scss" scoped>
.check-flow-index-bg {
  display: flex;
  height: calc(100vh - 70px);
}
.leftTree {
  width: 260px;
  padding-top: 20px;
  border-right: 1px solid #ccc;
  overflow: auto;
}
.check-flow-page-title {
  font-size: 16px;
  color: #333333;
  font-weight: bold;
  display: flex;
  align-items: center;
}
.check-flow-page-title-line {
  width: 4px;
  background-color: #1d6ced;
  height: 16px;
  margin-right: 8px;
}
.check-flow-page-right {
  padding: 20px 20px;
}
.check-flow-page-save {
  width: 900px;
  height: 48px;
  background-color: #eee;
  margin-top: 20px;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  .el-button {
    margin-left: 9px;
    width: 70px;
  }
}
.check-flow-page-content {
  width: 900px;
  overflow: auto;
  margin-top: 16px;
  height: calc(100% - 124px);
  display: flex;
}
.check-flow-panel {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 0 32px 32px;
  flex: 1 0 auto;
}
.check-flow-panel-title-bg {
  width: 220px;
  display: flex;
  flex-direction: column;
}
.check-flow-panel-title-block {
  height: 22px;
  line-height: 22px;
  font-size: 12px;
  color: #fff;
  width: 100%;
  border-radius: 5px;
  padding-left: 8px;
  background-color: #1d6ced;
}
.check-flow-right-slide-block {
  transition: right ease-out 0.3s;
  position: absolute;
  top: 0;
  z-index: 2;
  right: -400px;
  width: 400px;
  height: 100vh;
  background-color: white;
  .check-flow-right-slide-block-title {
    height: 50px;
    display: flex;
    align-items: center;
    border-bottom: 1px solid #ccc;
    .check-flow-right-slide-block-title-text {
      margin-left: 30px;
      font-size: 14px;
      line-height: 1;
      color: #333;
      display: flex;
      align-items: center;
      white-space: nowrap;
      .check-flow-desc-error {
        color: #e74c3c;
        font-size: 14px;
        margin-left: 4px;
      }
    }
    .el-button {
      margin-left: 4px;
      border: none;
    }
  }
  .check-flow-right-slide-block-middle {
    padding: 20px 30px 30px;
    border-bottom: 1px solid #ccc;
  }
  .condition-block-middle {
    border-bottom: 0;
  }
  .check-flow-right-slide-block-middle-top {
    margin-bottom: 30px;
    .el-radio {
      font-size: 12px;
      color: #333;
    }
  }
  .check-flow-right-slide-block-middle-selected {
    margin-top: 8px;
    .el-button {
      margin-left: 16px;
    }
  }
  .check-flow-right-slide-block-countersign {
    border-bottom: 1px solid #ccc;
    padding: 20px 30px;
  }
  .check-flow-right-slide-block-bottom {
    padding: 10px 10px 0;
    .check-flow-right-slide-block-bottom-title {
      font-size: 14px;
      line-height: 1;
      color: #333;
    }
    .check-flow-right-slide-block-bottom-option {
      margin-top: 30px;
      .el-radio + .el-radio {
        margin-top: 20px;
      }
    }
  }
  .check-flow-right-slide-block-action {
    position: absolute;
    bottom: 0;
    height: 76px;
    width: 400px;
    display: flex;
    align-items: center;
    justify-content: flex-end;
    background-color: #f6f6f6;
    .el-button:last-of-type {
      margin-right: 30px;
    }
  }
  .condition-block-middle-content {
    overflow-y: auto;
    margin-top: 8px;
    height: calc(100vh - 144px);
  }
  .condition-block-middle-seperator {
    margin-top: 8px;
    height: 1px;
    width: 100%;
    background-color: #ccc;
  }
  .condition-block-middle-content-block {
    padding: 8px 0;
  }
  .condition-block-middle-content-value {
    margin-top: 4px;
    display: flex;
  }
  .condition-block-middle-content-delete {
    margin-top: 8px;
  }
  .condition-name {
    font-size: 14px;
  }
  .condition-content {
    display: flex;
  }
  .condition-content-input {
    margin-left: 4px;
  }
}
.check-flow-right-slide-block-bg {
  background-color: black;
  opacity: 0.4;
  position: absolute;
  width: 100vw;
  height: 100vh;
  z-index: 1;
  top: 0;
  left: 0;
}
.dialog-content {
  display: flex;
  margin: -30px -20px;
}
.dialog-left {
  width: 50%;
  padding: 20px 0 32px 32px;
}
.dialog-part-title {
  font-size: 14px;
  color: #333;
}
.dialog-left-search {
  margin-top: 22px;
  width: 240px;
}
.dialog-left-tree {
  margin-top: 30px;
  max-height: 300px;
  overflow: auto;
}
.dialog-selected-zone {
  width: 50%;
  padding: 20px;
  background-color: #eee;
}
.dialog-selected-item {
  padding: 0 20px 0 10px;
  height: 36px;
  width: 280px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  background-color: white;
  border-radius: 4px;
  margin-top: 20px;
}
.dialog-selected-item + .dialog-selected-item {
  margin-top: 8px;
}
.check-flow-desc-label::before {
  content: "*";
  color: #f56c6c;
  margin-right: 4px;
}
.check-flow-desc-input {
  margin-left: 8px;
}
</style>
