<template>
  <div class="property-panel common-scroll-div" ref="propertyPanel">
    <el-collapse v-model="activeName">
      <el-collapse-item name="processDefinitionInfo">
        <template slot="title">
          <span class="iconfont icon-flowChart"></span>
          <span>流程定义信息</span>
        </template>
        <el-form label-position="top" inline size="small">
          <ht-form-item label="分类">
            <eip-sys-type-selector
              placeholder="请选择分类"
              type-key="FLOW_TYPE"
              v-model="modelData.typeName"
              :sys-type-id.sync="modelData.typeId"
              :validate="{required: true}"
            />
          </ht-form-item>
          <ht-form-item label="流程名称">
            <ht-input
              v-model="rootElements.name"
              placeholder=""
              :validate="{
                required: true,
                regex: {
                  exp: '^.{1,30}$',
                  message: '长度不能超过30'
                }
              }"
              @input="value => updateRootElementProperties({name: value})"
              @change="flowNameChange"
            >
              <el-button
                icon="icon-guojihua"
                slot="append"
                style="width: 80px"
                @click="editI18nMessage(`flow.${rootElements.id}`)"
                >国际化</el-button
              >
            </ht-input>
          </ht-form-item>
          <ht-form-item label="流程key">
            <ht-input
              v-model="rootElements.id"
              :disabled="modelData.defId.length > 0"
              v-pinyin="rootElements.name"
              :validate="{
                required: true,
                alpha_dash: true,
                regex: {
                  exp: '^[^0-9][\\w]{1,29}$',
                  message: '只能输入字母开头的不超过30位的key'
                }
              }"
              placeholder=""
              @input="value => updateRootElementProperties({id: value})"
            ></ht-input>
          </ht-form-item>
          <ht-form-item label="流程描述">
            <ht-input
              v-model="modelData.desc"
              type="textarea"
              placeholder=""
              :maxlength="500"
              :showWordLimit="true"
            ></ht-input>
          </ht-form-item>
          <ht-form-item
            label="修改原因"
            label-width="70px"
            v-if="modelData.version"
          >
            <ht-input
              v-model="modelData.reason"
              type="textarea"
              placeholder=""
            ></ht-input>
          </ht-form-item>
          <ht-form-item
            label="版本号"
            label-width="70px"
            v-if="modelData.version"
          >
            <el-input
              v-model="modelData.version"
              placeholder=""
              disabled
            ></el-input>
          </ht-form-item>
        </el-form>
      </el-collapse-item>
      <el-collapse-item name="nodeProperty" v-if="isChecked">
        <template slot="title">
          <span class="iconfont icon-property"></span>
          <span>属性设置</span>
        </template>
        <el-form
          :model="form"
          data-vv-scope="form1"
          label-position="top"
          size="small"
          inline
        >
          <ht-form-item label="节点ID">
            <ht-input
              v-model="form.id"
              :disabled="processStatus == 'deploy' ? true : false"
              @input="value => updateProperties({id: value})"
              :validate="{
                required: true,
                alpha_dash: true,
                regex: {
                  exp: '^[a-zA-Z][\\s\\S]{1,60}$',
                  message: '字母开头字母数字下划线，最长60'
                }
              }"
            ></ht-input> </ht-form-item
          ><br />
          <ht-form-item label="节点名称">
            <ht-input v-model="form.name" @input="nameChange" show-word-limit :maxlength="20">
              <el-button
                icon="icon-guojihua"
                slot="append"
                style="width: 80px"
                @click="editI18nMessage(`flow.${rootElements.id}.${form.id}`)"
                >国际化</el-button
              >
            </ht-input> </ht-form-item
          ><br />

          <!-- 子流程key -->
          <el-form-item label="子流程key" v-if="callActivity">
            <el-input
              v-model="form.callActivityDefKey"
              placeholder="请选择"
              disabled
              style="width: 200px"
            >
              <el-button
                slot="append"
                icon="el-icon-search"
                @click="$refs.eipFlowDialog.showDialog()"
              ></el-button
            ></el-input>
          </el-form-item>
        </el-form>
      </el-collapse-item>
    </el-collapse>
    <!-- 流程选择对话框  -->
    <eip-flow-dialog
      ref="eipFlowDialog"
      name="eipFlowDialog"
      single
      @onConfirm="selectFlowOnConfirm"
      append-to-body
    />
    <i18n-message-edit ref="i18nMessageEdit" :messageKey="i18nMessageKey" />
  </div>
</template>

<script>
const eipFlowDialog = () => import('@/components/dialog/EipFlowDialog.vue')
const EipSysTypeSelector = () =>
  import('@/components/selector/EipSysTypeSelector.vue')
import {mixins} from '@/mixins/index'
import {changeElementSize} from '@/components/VueBpmn/custom/util'
import {is} from 'bpmn-js/lib/util/ModelUtil'
import i18nMessageEdit from '@/components/system/I18nMessageEdit.vue'
export default {
  name: 'FlowBasicPropertyPanel',
  mixins: [mixins],
  props: {
    modeler: {
      type: Object,
      required: true
    },
    modelData: {
      type: Object,
      required: true
    },
    processStatus: {
      type: String,
      default: ''
    }
  },
  components: {eipFlowDialog, EipSysTypeSelector, i18nMessageEdit},
  computed: {
    userTask() {
      if (!this.element) {
        return
      }
      let isUserTask = this.element.type === 'bpmn:UserTask'
      return isUserTask
    },
    sequenceFlow() {
      if (!this.element) {
        return
      }
      return this.element.type === 'bpmn:SequenceFlow'
    },
    sequenceFlowSource() {
      if (!this.element) {
        return {
          type: ''
        }
      }
      return this.element.source
    },
    exclusiveGateway() {
      if (!this.element) {
        return
      }

      return this.element.type === 'bpmn:ExclusiveGateway'
    },
    // 内嵌子流程
    subProcess() {
      if (!this.element) {
        return
      }

      return this.element.type === 'bpmn:SubProcess'
    },
    // 外部子流程
    callActivity() {
      if (!this.element) {
        return
      }

      return this.element.type === 'bpmn:CallActivity'
    }
  },
  data() {
    return {
      rootElements: this.modeler.getDefinitions().rootElements.find(item => {
        return item.$type == 'bpmn:Process'
      }),
      form: {
        id: '',
        name: '',
        color: null,
        ismultiinstance: 'signleinstance',
        multiinstancetype: '',
        callActivityDefKey: ''
      },
      flowElementsConfig: {},
      outgoing: [],
      element: {
        id: null,
        businessObject: {
          id: '',
          name: ''
        }
      },
      activeName: ['processDefinitionInfo', 'nodeProperty'],
      users: [
        {
          value: 'zhangsan',
          label: '张三'
        },
        {
          value: 'lisi',
          label: '李四'
        },
        {
          value: 'wangwu',
          label: '王五'
        }
      ],
      roles: [
        {
          value: 'manager',
          label: '经理'
        },
        {
          value: 'personnel',
          label: '人事'
        },
        {
          value: 'charge',
          label: '主管'
        }
      ],
      i18nMessageKey: '',
      isChecked: false
    }
  },
  mounted() {
    this.handleModeler()

    this.$watch(
      function() {
        // 第一个函数就是处理你要监听的属性，只要将其return出去就行
        return (
          this.modeler._definitions &&
          this.modeler._definitions.rootElements &&
          this.modeler._definitions.rootElements[0].flowElements
        )
      },
      function(val, oldval) {
        if (val && val != oldval) {
        }
      },
      {deep: true, immediate: true}
    )
  },
  methods: {
    selectFlowOnConfirm(data) {
      if (data && data.length == 1) {
        this.element.businessObject['calledElement'] = data[0].defKey
        this.element.businessObject['inheritVariables'] = 'true'
        this.element.businessObject.name = data[0].name
        this.form.name = data[0].name
        this.form.callActivityDefKey = data[0].defKey
      }
    },
    updateloopCharacteristicsProperty() {
      let expression = this.callActivity
        ? '${actUserService.getExtSubProcessMultipleUser(execution)}'
        : '${actUserService.getSubProcessUser(execution)}'

      this.element.businessObject.loopCharacteristics['collection'] = expression
      this.element.businessObject.loopCharacteristics['elementVariable'] =
        'assignee'
    },
    forceUpdate() {
      this.$forceUpdate()
    },
    getExtensionElementValues(flowElement, type) {
      let extensionElement = flowElement.extensionElements.values.filter(
        extensionElement => {
          return extensionElement.$instanceOf(type)
        }
      )[0]
      if (extensionElement && extensionElement.values) {
        return extensionElement.values
      }
      return []
    },
    handleModeler() {
      var eventBus = this.modeler.get('eventBus')
      // 第一次渲染时修改图的大小
      this.modeler.on('commandStack.shape.create.preExecute', e => {
        changeElementSize(e.context.shape)
      })

      this.modeler.on('commandStack.shape.create.execute', e => {})

      // 监听节点选择变化
      this.modeler.on('selection.changed', e => {
        const element = e.newSelection[0]
        if (!element) return
        this.element = element
        this.form = {
          ...element.businessObject,
          ...element.businessObject.$attrs
        }
        this.isChecked = true
        this.handlerExtensionElements(element)
      })

      //  监听节点属性变化
      this.modeler.on('element.changed', (e, l) => {
        const {element} = e
        if (!element) return

        this.element = element
        this.updateId(element)
        this.form = {
          ...element.businessObject,
          ...element.businessObject.$attrs
        }
        this.handlerExtensionElements(this.element)
      })
    },
    updateId(element) {
      if (!is(element, 'bpmn:UserTask') || element.id != this.form.id) {
        return
      }
      // 用户任务 改为会签任务时  id 需要改变
      // 会签任务变为用户任务时 id 需要改变
      if (
        (!this.form.loopCharacteristics &&
          element.businessObject.loopCharacteristics) ||
        (this.form.loopCharacteristics &&
          !element.businessObject.loopCharacteristics)
      ) {
        element.businessObject.id = element.id
        if (!element.tempFlag) {
          element.tempFlag = true
          let prefix = 'UserTask_'
          if (
            !this.form.loopCharacteristics &&
            element.businessObject.loopCharacteristics
          ) {
            prefix = 'SignTask_'
          }
          this.updateProperties({
            id: this.modeler._moddle.ids.nextPrefixed(prefix, element)
          })
        } else {
          delete element.tempFlag
        }
      }
    },
    handlerExtensionElements(element) {
      let userTaskListener = [
        {event: 'create', delegateExpression: '${taskCreateListener}'},
        {event: 'complete', delegateExpression: '${taskCompleteListener}'}
      ]
      let signUserTaskListener = [
        {event: 'create', delegateExpression: '${taskSignCreateListener}'},
        {event: 'complete', delegateExpression: '${taskCompleteListener}'}
      ]
      // 内嵌子流程
      let subProcessExecutionListener = [
        {event: 'start', delegateExpression: '${subProcessStartListener}'},
        {event: 'end', delegateExpression: '${subProcessEndListener}'}
      ]
      // 外部子流程
      let callActivityExecutionListener = [
        {
          event: 'start',
          delegateExpression: '${callSubProcessStartListener}'
        },
        {event: 'end', delegateExpression: '${callSubProcessEndListener}'}
      ]
      let extensionElements = null
      switch (element.type) {
        case 'bpmn:UserTask':
          extensionElements = this.getOrCreateExtensionElements(element)
          // 判断是否是会签任务
          if (
            element.businessObject &&
            element.businessObject.loopCharacteristics
          ) {
            // 设置会签任务相关的taskListener
            extensionElements.values = this.createListener(
              'activiti:TaskListener',
              signUserTaskListener
            )

            const modeling = this.modeler.get('modeling')
            const moddle = this.modeler.get('moddle')

            var completionCondition = moddle.create('bpmn:FormalExpression', {
              body: '${signComplete.isComplete(execution)}'
            })
            element.businessObject.loopCharacteristics[
              'completionCondition'
            ] = completionCondition
            element.businessObject.loopCharacteristics['collection'] =
              '${actUserService.getSignUser(execution)}'
            element.businessObject.loopCharacteristics['elementVariable'] =
              'assignee'
          } else {
            // 设置用户任务相关的taskListener
            extensionElements.values = this.createListener(
              'activiti:TaskListener',
              userTaskListener
            )
          }

          break
        // 服务任务处理
        case 'bpmn:ServiceTask':
          if (element.businessObject.extensionElements) {
            delete element.businessObject.extensionElements
          }
          element.businessObject['delegateExpression'] = '${customServiceTask}'

          break
        // 内部子流程处理
        case 'bpmn:SubProcess':
          extensionElements = this.getOrCreateExtensionElements(element)
          extensionElements.values = this.createListener(
            'activiti:ExecutionListener',
            subProcessExecutionListener
          )

          break
        // 外部子流程处理
        case 'bpmn:CallActivity':
          extensionElements = this.getOrCreateExtensionElements(element)
          extensionElements.values = this.createListener(
            'activiti:ExecutionListener',
            callActivityExecutionListener
          )
          this.form.callActivityDefKey = element.businessObject.calledElement
          break

        default:
          break
      }

      if (
        element.type == 'bpmn:CallActivity' ||
        element.type == 'bpmn:SubProcess'
      ) {
        if (element.businessObject.loopCharacteristics) {
          this.updateloopCharacteristicsProperty()
        }
      }
    },
    // 属性面板名称，更新回流程节点
    nameChange(name) {
      const modeling = this.modeler.get('modeling')
      modeling.updateLabel(this.element, name)
    },
    // 属性面板颜色，更新回流程节点
    colorChange(color) {
      const modeling = this.modeler.get('modeling')
      modeling.setColor(this.element, {
        fill: null,
        stroke: color
      })
      modeling.updateProperties(this.element, {
        color: color
      })
    },
    getOrCreateExtensionElements(element) {
      var bo = element.businessObject

      var extensionElements = bo.extensionElements

      // add extension elements
      if (!extensionElements) {
        extensionElements = this.modeler._moddle.create(
          'bpmn:ExtensionElements',
          {
            values: []
          }
        )
        const modeling = this.modeler.get('modeling')
        modeling.updateProperties(element, {
          extensionElements: extensionElements
        })
      }

      return extensionElements
    },
    // 创建 bpmn:ExtensionElements 下级元素
    getOrCreateElements(elementname, childElements) {
      const moddle = this.modeler.get('moddle')
      const modeling = this.modeler.get('modeling')
      let businessObject = this.element.businessObject
      const extensionElements = this.getOrCreateExtensionElements(this.element)
      let elements = this.getExtensionElement(businessObject, elementname)
      if (!elements) {
        elements = moddle.create(elementname, {
          values: []
        })
        extensionElements.get('values').push(elements)
      }

      if (childElements) {
        elements.values = []
        elements.values = elements.values.concat(childElements)
      }

      modeling.updateProperties(this.element, {
        extensionElements: extensionElements
      })
      return elements.values || []
    },
    createListener(elementName, taskListenersArr) {
      const moddle = this.modeler.get('moddle')
      let taskListeners = []
      taskListenersArr.forEach(temp => {
        let taskListener = moddle.create(elementName)
        taskListener.event = temp.event
        taskListener.delegateExpression = temp.delegateExpression
        taskListeners.push(taskListener)
      })
      return taskListeners
    },
    // 任务节点配置人员
    addUser(properties) {
      this.updateProperties(
        Object.assign(properties, {
          userType: Object.keys(properties)[0]
        })
      )
    },
    // 切换人员类型
    typeChange() {
      const types = ['assignee', 'candidateUsers', 'candidateGroups']
      types.forEach(type => {
        delete this.element.businessObject.$attrs[type]
        delete this.form[type]
      })
    },
    getConditionExpression(outgoing) {
      this.outgoing = outgoing
    },
    // 在这里我们封装一个通用的更新节点属性的方法
    updateProperties(properties) {
      const modeling = this.modeler.get('modeling')
      modeling.updateProperties(this.element, properties)
    },
    // 更新根节点属性
    updateRootElementProperties(properties) {
      for (var key in properties) {
        this.modeler.getDefinitions().rootElements.find(item => {
          return item.$type == 'bpmn:Process'
        })[key] = properties[key]
      }
    },
    flowNameChange() {
      this.$nextTick(() => {
        this.updateRootElementProperties({id: this.rootElements.id})
      })
    },
    editI18nMessage(data) {
      this.i18nMessageKey = data
      this.$refs.i18nMessageEdit.handleOpen()
    }
  }
}
</script>

<style lang="scss" scoped>
.property-panel {
  // position: absolute;
  // right: 0px;
  // top: 0px;
  // border-left: 1px solid #cccccc;
  // padding: 20px 0;
  height: 100%;
  // width: 100%;
  background: #f5f5f5;
  overflow-y: auto;
  /deep/ .el-collapse-item__header {
    background-color: transparent;
    border-bottom: 1px solid #e0e0e0;
    color: #333333;
    font-size: 16px;
    height: 62px;
    line-height: 62px;
    padding-left: 15px;
    .iconfont {
      margin-right: 10px;
    }
    span {
      font-size: 16px;
    }
  }
  /deep/ .el-collapse-item__content {
    padding: 15px;

    .el-form-item {
      margin-bottom: 10px;
      width: 100%;

      .inputs {
        width: 100%;
      }
    }
    .el-form--label-top .el-form-item__label {
      padding: 0;
    }
  }
}

/deep/ .el-collapse-item__wrap {
  background: #f5f5f5;
}
/deep/ span > small.el-form-item__error {
  display: inline-block;
}
/deep/ .el-textarea .el-input__count {
  height: 20px;
  line-height: 20px;
}
</style>
