路由及相应重构回退vxe
							parent
							
								
									561b617ca4
								
							
						
					
					
						commit
						af26859ba8
					
				| 
						 | 
				
			
			@ -225,26 +225,26 @@ const remainingRouter: AppRouteRecordRaw[] = [
 | 
			
		|||
    children: [
 | 
			
		||||
      {
 | 
			
		||||
        path: '/manager/form/edit',
 | 
			
		||||
        component: () => import('@/views/bpm/form/editor/index.vue'),
 | 
			
		||||
        component: () => import('@/views/bpm/form/formEditor.vue'),
 | 
			
		||||
        name: 'bpmFormEditor',
 | 
			
		||||
        meta: {
 | 
			
		||||
          noCache: true,
 | 
			
		||||
          hidden: true,
 | 
			
		||||
          canTo: true,
 | 
			
		||||
          title: '设计流程表单',
 | 
			
		||||
          activeMenu: '/bpm/manager/form'
 | 
			
		||||
          activeMenu: '/bpm/manager/formEditor'
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: '/manager/model/edit',
 | 
			
		||||
        component: () => import('@/views/bpm/model/editor/index.vue'),
 | 
			
		||||
        component: () => import('@/views/bpm/model/modelEditor.vue'),
 | 
			
		||||
        name: 'modelEditor',
 | 
			
		||||
        meta: {
 | 
			
		||||
          noCache: true,
 | 
			
		||||
          hidden: true,
 | 
			
		||||
          canTo: true,
 | 
			
		||||
          title: '设计流程',
 | 
			
		||||
          activeMenu: '/bpm/manager/model'
 | 
			
		||||
          activeMenu: '/bpm/manager/design'
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
| 
						 | 
				
			
			@ -256,7 +256,7 @@ const remainingRouter: AppRouteRecordRaw[] = [
 | 
			
		|||
          hidden: true,
 | 
			
		||||
          canTo: true,
 | 
			
		||||
          title: '流程定义',
 | 
			
		||||
          activeMenu: '/bpm/manager/model'
 | 
			
		||||
          activeMenu: '/bpm/definition/index'
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
| 
						 | 
				
			
			@ -272,7 +272,7 @@ const remainingRouter: AppRouteRecordRaw[] = [
 | 
			
		|||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: '/process-instance/create',
 | 
			
		||||
        component: () => import('@/views/bpm/processInstance/create/index.vue'),
 | 
			
		||||
        component: () => import('@/views/bpm/processInstance/create.vue'),
 | 
			
		||||
        name: 'BpmProcessInstanceCreate',
 | 
			
		||||
        meta: {
 | 
			
		||||
          noCache: true,
 | 
			
		||||
| 
						 | 
				
			
			@ -284,7 +284,7 @@ const remainingRouter: AppRouteRecordRaw[] = [
 | 
			
		|||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: '/process-instance/detail',
 | 
			
		||||
        component: () => import('@/views/bpm/processInstance/detail/index.vue'),
 | 
			
		||||
        component: () => import('@/views/bpm/processInstance/detail.vue'),
 | 
			
		||||
        name: 'BpmProcessInstanceDetail',
 | 
			
		||||
        meta: {
 | 
			
		||||
          noCache: true,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,106 +0,0 @@
 | 
			
		|||
<template>
 | 
			
		||||
  <ContentWrap>
 | 
			
		||||
    <!-- 表单设计器 -->
 | 
			
		||||
    <fc-designer ref="designer" height="780px">
 | 
			
		||||
      <template #handle>
 | 
			
		||||
        <el-button round size="small" type="primary" @click="handleSave">
 | 
			
		||||
          <Icon icon="ep:plus" class="mr-5px" /> 保存
 | 
			
		||||
        </el-button>
 | 
			
		||||
      </template>
 | 
			
		||||
    </fc-designer>
 | 
			
		||||
  </ContentWrap>
 | 
			
		||||
 | 
			
		||||
  <!-- 表单保存的弹窗 -->
 | 
			
		||||
  <Dialog title="保存表单" v-model="modelVisible" width="600">
 | 
			
		||||
    <el-form ref="formRef" :model="formData" :rules="formRules" label-width="80px">
 | 
			
		||||
      <el-form-item label="表单名" prop="name">
 | 
			
		||||
        <el-input v-model="formData.name" placeholder="请输入表单名" />
 | 
			
		||||
      </el-form-item>
 | 
			
		||||
      <el-form-item label="状态" prop="status">
 | 
			
		||||
        <el-radio-group v-model="formData.status">
 | 
			
		||||
          <el-radio
 | 
			
		||||
            v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
 | 
			
		||||
            :key="dict.value"
 | 
			
		||||
            :label="dict.value"
 | 
			
		||||
          >
 | 
			
		||||
            {{ dict.label }}
 | 
			
		||||
          </el-radio>
 | 
			
		||||
        </el-radio-group>
 | 
			
		||||
      </el-form-item>
 | 
			
		||||
      <el-form-item label="备注" prop="remark">
 | 
			
		||||
        <el-input v-model="formData.remark" type="textarea" placeholder="请输入备注" />
 | 
			
		||||
      </el-form-item>
 | 
			
		||||
    </el-form>
 | 
			
		||||
    <template #footer>
 | 
			
		||||
      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
 | 
			
		||||
      <el-button @click="modelVisible = false">取 消</el-button>
 | 
			
		||||
    </template>
 | 
			
		||||
  </Dialog>
 | 
			
		||||
</template>
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
 | 
			
		||||
import { CommonStatusEnum } from '@/utils/constants'
 | 
			
		||||
import * as FormApi from '@/api/bpm/form'
 | 
			
		||||
import { encodeConf, encodeFields, setConfAndFields } from '@/utils/formCreate'
 | 
			
		||||
 | 
			
		||||
const { t } = useI18n() // 国际化
 | 
			
		||||
const message = useMessage() // 消息
 | 
			
		||||
const { query } = useRoute() // 路由
 | 
			
		||||
 | 
			
		||||
const designer = ref() // 表单设计器
 | 
			
		||||
const modelVisible = ref(false) // 弹窗是否展示
 | 
			
		||||
const formLoading = ref(false) // 表单的加载中:提交的按钮禁用
 | 
			
		||||
const formData = ref({
 | 
			
		||||
  name: '',
 | 
			
		||||
  status: CommonStatusEnum.ENABLE,
 | 
			
		||||
  remark: ''
 | 
			
		||||
})
 | 
			
		||||
const formRules = reactive({
 | 
			
		||||
  name: [{ required: true, message: '表单名不能为空', trigger: 'blur' }],
 | 
			
		||||
  status: [{ required: true, message: '开启状态不能为空', trigger: 'blur' }]
 | 
			
		||||
})
 | 
			
		||||
const formRef = ref() // 表单 Ref
 | 
			
		||||
 | 
			
		||||
/** 处理保存按钮 */
 | 
			
		||||
const handleSave = () => {
 | 
			
		||||
  modelVisible.value = true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 提交表单 */
 | 
			
		||||
const submitForm = async () => {
 | 
			
		||||
  // 校验表单
 | 
			
		||||
  if (!formRef) return
 | 
			
		||||
  const valid = await formRef.value.validate()
 | 
			
		||||
  if (!valid) return
 | 
			
		||||
  // 提交请求
 | 
			
		||||
  formLoading.value = true
 | 
			
		||||
  try {
 | 
			
		||||
    const data = formData.value as FormApi.FormVO
 | 
			
		||||
    data.conf = encodeConf(designer) // 表单配置
 | 
			
		||||
    data.fields = encodeFields(designer) // 表单字段
 | 
			
		||||
    if (!data.id) {
 | 
			
		||||
      await FormApi.createFormApi(data)
 | 
			
		||||
      message.success(t('common.createSuccess'))
 | 
			
		||||
    } else {
 | 
			
		||||
      await FormApi.updateFormApi(data)
 | 
			
		||||
      message.success(t('common.updateSuccess'))
 | 
			
		||||
    }
 | 
			
		||||
    modelVisible.value = false
 | 
			
		||||
  } finally {
 | 
			
		||||
    formLoading.value = false
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 初始化 **/
 | 
			
		||||
onMounted(async () => {
 | 
			
		||||
  // 场景一:新增表单
 | 
			
		||||
  const id = query.id as unknown as number
 | 
			
		||||
  if (!id) {
 | 
			
		||||
    return
 | 
			
		||||
  }
 | 
			
		||||
  // 场景二:修改表单
 | 
			
		||||
  const data = await FormApi.getFormApi(id)
 | 
			
		||||
  formData.value = data
 | 
			
		||||
  setConfAndFields(designer, data.conf, data.fields)
 | 
			
		||||
})
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			@ -1,102 +0,0 @@
 | 
			
		|||
<template>
 | 
			
		||||
  <ContentWrap>
 | 
			
		||||
    <!-- 流程设计器,负责绘制流程等 -->
 | 
			
		||||
    <my-process-designer
 | 
			
		||||
      key="designer"
 | 
			
		||||
      v-if="xmlString !== undefined"
 | 
			
		||||
      v-model="xmlString"
 | 
			
		||||
      :value="xmlString"
 | 
			
		||||
      v-bind="controlForm"
 | 
			
		||||
      keyboard
 | 
			
		||||
      ref="processDesigner"
 | 
			
		||||
      @init-finished="initModeler"
 | 
			
		||||
      :additionalModel="controlForm.additionalModel"
 | 
			
		||||
      @save="save"
 | 
			
		||||
    />
 | 
			
		||||
    <!-- 流程属性器,负责编辑每个流程节点的属性 -->
 | 
			
		||||
    <my-properties-panel
 | 
			
		||||
      key="penal"
 | 
			
		||||
      :bpmnModeler="modeler"
 | 
			
		||||
      :prefix="controlForm.prefix"
 | 
			
		||||
      class="process-panel"
 | 
			
		||||
      :model="model"
 | 
			
		||||
    />
 | 
			
		||||
  </ContentWrap>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
// 自定义元素选中时的弹出菜单(修改 默认任务 为 用户任务)
 | 
			
		||||
import CustomContentPadProvider from '@/components/bpmnProcessDesigner/package/designer/plugins/content-pad'
 | 
			
		||||
// 自定义左侧菜单(修改 默认任务 为 用户任务)
 | 
			
		||||
import CustomPaletteProvider from '@/components/bpmnProcessDesigner/package/designer/plugins/palette'
 | 
			
		||||
import * as ModelApi from '@/api/bpm/model'
 | 
			
		||||
 | 
			
		||||
const router = useRouter() // 路由
 | 
			
		||||
const { query } = useRoute() // 路由的查询
 | 
			
		||||
const message = useMessage() // 国际化
 | 
			
		||||
 | 
			
		||||
const xmlString = ref(undefined) // BPMN XML
 | 
			
		||||
const modeler = ref(null) // BPMN Modeler
 | 
			
		||||
const controlForm = ref({
 | 
			
		||||
  simulation: true,
 | 
			
		||||
  labelEditing: false,
 | 
			
		||||
  labelVisible: false,
 | 
			
		||||
  prefix: 'flowable',
 | 
			
		||||
  headerButtonSize: 'mini',
 | 
			
		||||
  additionalModel: [CustomContentPadProvider, CustomPaletteProvider]
 | 
			
		||||
})
 | 
			
		||||
const model = ref<ModelApi.ModelVO>() // 流程模型的信息
 | 
			
		||||
 | 
			
		||||
/** 初始化 modeler */
 | 
			
		||||
const initModeler = (item) => {
 | 
			
		||||
  setTimeout(() => {
 | 
			
		||||
    modeler.value = item
 | 
			
		||||
  }, 10)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 添加/修改模型 */
 | 
			
		||||
const save = async (bpmnXml) => {
 | 
			
		||||
  const data = {
 | 
			
		||||
    ...model.value,
 | 
			
		||||
    bpmnXml: bpmnXml // bpmnXml 只是初始化流程图,后续修改无法通过它获得
 | 
			
		||||
  } as unknown as ModelApi.ModelVO
 | 
			
		||||
  // 提交
 | 
			
		||||
  if (data.id) {
 | 
			
		||||
    await ModelApi.updateModelApi(data)
 | 
			
		||||
    message.success('修改成功')
 | 
			
		||||
  } else {
 | 
			
		||||
    await ModelApi.createModelApi(data)
 | 
			
		||||
    message.success('新增成功')
 | 
			
		||||
  }
 | 
			
		||||
  // 跳转回去
 | 
			
		||||
  close()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 关闭按钮 */
 | 
			
		||||
const close = () => {
 | 
			
		||||
  router.push({ path: '/bpm/manager/model' })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 初始化 */
 | 
			
		||||
onMounted(async () => {
 | 
			
		||||
  const modelId = query.modelId as unknown as number
 | 
			
		||||
  if (!modelId) {
 | 
			
		||||
    message.error('缺少模型 modelId 编号')
 | 
			
		||||
    return
 | 
			
		||||
  }
 | 
			
		||||
  // 查询模型
 | 
			
		||||
  const data = await ModelApi.getModelApi(modelId)
 | 
			
		||||
  xmlString.value = data.bpmnXml
 | 
			
		||||
  model.value = {
 | 
			
		||||
    ...data,
 | 
			
		||||
    bpmnXml: undefined // 清空 bpmnXml 属性
 | 
			
		||||
  }
 | 
			
		||||
})
 | 
			
		||||
</script>
 | 
			
		||||
<style lang="scss">
 | 
			
		||||
.process-panel__container {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  right: 60px;
 | 
			
		||||
  top: 90px;
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
| 
						 | 
				
			
			@ -1,130 +0,0 @@
 | 
			
		|||
<template>
 | 
			
		||||
  <!-- 第一步,通过流程定义的列表,选择对应的流程 -->
 | 
			
		||||
  <ContentWrap v-if="!selectProcessInstance">
 | 
			
		||||
    <el-table v-loading="loading" :data="list">
 | 
			
		||||
      <el-table-column label="流程名称" align="center" prop="name" />
 | 
			
		||||
      <el-table-column label="流程分类" align="center" prop="category">
 | 
			
		||||
        <template #default="scope">
 | 
			
		||||
          <dict-tag :type="DICT_TYPE.BPM_MODEL_CATEGORY" :value="scope.row.category" />
 | 
			
		||||
        </template>
 | 
			
		||||
      </el-table-column>
 | 
			
		||||
      <el-table-column label="流程版本" align="center" prop="version">
 | 
			
		||||
        <template #default="scope">
 | 
			
		||||
          <el-tag>v{{ scope.row.version }}</el-tag>
 | 
			
		||||
        </template>
 | 
			
		||||
      </el-table-column>
 | 
			
		||||
      <el-table-column label="流程描述" align="center" prop="description" />
 | 
			
		||||
      <el-table-column label="操作" align="center">
 | 
			
		||||
        <template #default="scope">
 | 
			
		||||
          <el-button link type="primary" @click="handleSelect(scope.row)">
 | 
			
		||||
            <Icon icon="ep:plus" /> 选择
 | 
			
		||||
          </el-button>
 | 
			
		||||
        </template>
 | 
			
		||||
      </el-table-column>
 | 
			
		||||
    </el-table>
 | 
			
		||||
  </ContentWrap>
 | 
			
		||||
 | 
			
		||||
  <!-- 第二步,填写表单,进行流程的提交 -->
 | 
			
		||||
  <ContentWrap v-else>
 | 
			
		||||
    <el-card class="box-card">
 | 
			
		||||
      <div class="clearfix">
 | 
			
		||||
        <span class="el-icon-document">申请信息【{{ selectProcessInstance.name }}】</span>
 | 
			
		||||
        <el-button style="float: right" type="primary" @click="selectProcessInstance = undefined">
 | 
			
		||||
          <Icon icon="ep:delete" /> 选择其它流程
 | 
			
		||||
        </el-button>
 | 
			
		||||
      </div>
 | 
			
		||||
      <el-col :span="16" :offset="6" style="margin-top: 20px">
 | 
			
		||||
        <form-create
 | 
			
		||||
          :rule="detailForm.rule"
 | 
			
		||||
          v-model:api="fApi"
 | 
			
		||||
          :option="detailForm.option"
 | 
			
		||||
          @submit="submitForm"
 | 
			
		||||
        />
 | 
			
		||||
      </el-col>
 | 
			
		||||
    </el-card>
 | 
			
		||||
    <!-- 流程图预览 -->
 | 
			
		||||
    <ProcessInstanceBpmnViewer :bpmn-xml="bpmnXML" />
 | 
			
		||||
  </ContentWrap>
 | 
			
		||||
</template>
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { DICT_TYPE } from '@/utils/dict'
 | 
			
		||||
import * as DefinitionApi from '@/api/bpm/definition'
 | 
			
		||||
import * as ProcessInstanceApi from '@/api/bpm/processInstance'
 | 
			
		||||
import { setConfAndFields2 } from '@/utils/formCreate'
 | 
			
		||||
import type { ApiAttrs } from '@form-create/element-ui/types/config'
 | 
			
		||||
import ProcessInstanceBpmnViewer from '../detail/ProcessInstanceBpmnViewer.vue'
 | 
			
		||||
const router = useRouter() // 路由
 | 
			
		||||
const message = useMessage() // 消息
 | 
			
		||||
 | 
			
		||||
// ========== 列表相关 ==========
 | 
			
		||||
const loading = ref(true) // 列表的加载中
 | 
			
		||||
const list = ref([]) // 列表的数据
 | 
			
		||||
const queryParams = reactive({
 | 
			
		||||
  suspensionState: 1
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
/** 查询列表 */
 | 
			
		||||
const getList = async () => {
 | 
			
		||||
  loading.value = true
 | 
			
		||||
  try {
 | 
			
		||||
    list.value = await DefinitionApi.getProcessDefinitionList(queryParams)
 | 
			
		||||
  } finally {
 | 
			
		||||
    loading.value = false
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ========== 表单相关 ==========
 | 
			
		||||
const bpmnXML = ref(null) // BPMN 数据
 | 
			
		||||
const fApi = ref<ApiAttrs>()
 | 
			
		||||
const detailForm = ref({
 | 
			
		||||
  // 流程表单详情
 | 
			
		||||
  rule: [],
 | 
			
		||||
  option: {}
 | 
			
		||||
})
 | 
			
		||||
const selectProcessInstance = ref() // 选择的流程实例
 | 
			
		||||
 | 
			
		||||
/** 处理选择流程的按钮操作 **/
 | 
			
		||||
const handleSelect = async (row) => {
 | 
			
		||||
  // 设置选择的流程
 | 
			
		||||
  selectProcessInstance.value = row
 | 
			
		||||
 | 
			
		||||
  // 情况一:流程表单
 | 
			
		||||
  if (row.formType == 10) {
 | 
			
		||||
    // 设置表单
 | 
			
		||||
    setConfAndFields2(detailForm, row.formConf, row.formFields)
 | 
			
		||||
    // 加载流程图
 | 
			
		||||
    bpmnXML.value = await DefinitionApi.getProcessDefinitionBpmnXML(row.id)
 | 
			
		||||
    // 情况二:业务表单
 | 
			
		||||
  } else if (row.formCustomCreatePath) {
 | 
			
		||||
    await router.push({
 | 
			
		||||
      path: row.formCustomCreatePath
 | 
			
		||||
    })
 | 
			
		||||
    // 这里暂时无需加载流程图,因为跳出到另外个 Tab;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 提交按钮 */
 | 
			
		||||
const submitForm = async (formData) => {
 | 
			
		||||
  if (!fApi.value || !selectProcessInstance.value) {
 | 
			
		||||
    return
 | 
			
		||||
  }
 | 
			
		||||
  // 提交请求
 | 
			
		||||
  fApi.value.btn.loading(true)
 | 
			
		||||
  try {
 | 
			
		||||
    await ProcessInstanceApi.createProcessInstanceApi({
 | 
			
		||||
      processDefinitionId: selectProcessInstance.value.id,
 | 
			
		||||
      variables: formData
 | 
			
		||||
    })
 | 
			
		||||
    // 提示
 | 
			
		||||
    message.success('发起流程成功')
 | 
			
		||||
    router.go(-1)
 | 
			
		||||
  } finally {
 | 
			
		||||
    fApi.value.btn.loading(false)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 初始化 */
 | 
			
		||||
onMounted(() => {
 | 
			
		||||
  getList()
 | 
			
		||||
})
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			@ -1,277 +0,0 @@
 | 
			
		|||
<template>
 | 
			
		||||
  <ContentWrap>
 | 
			
		||||
    <!-- 审批信息 -->
 | 
			
		||||
    <el-card
 | 
			
		||||
      class="box-card"
 | 
			
		||||
      v-loading="processInstanceLoading"
 | 
			
		||||
      v-for="(item, index) in runningTasks"
 | 
			
		||||
      :key="index"
 | 
			
		||||
    >
 | 
			
		||||
      <template #header>
 | 
			
		||||
        <span class="el-icon-picture-outline">审批任务【{{ item.name }}】</span>
 | 
			
		||||
      </template>
 | 
			
		||||
      <el-col :span="16" :offset="6">
 | 
			
		||||
        <el-form
 | 
			
		||||
          :ref="'form' + index"
 | 
			
		||||
          :model="auditForms[index]"
 | 
			
		||||
          :rules="auditRule"
 | 
			
		||||
          label-width="100px"
 | 
			
		||||
        >
 | 
			
		||||
          <el-form-item label="流程名" v-if="processInstance && processInstance.name">
 | 
			
		||||
            {{ processInstance.name }}
 | 
			
		||||
          </el-form-item>
 | 
			
		||||
          <el-form-item label="流程发起人" v-if="processInstance && processInstance.startUser">
 | 
			
		||||
            {{ processInstance.startUser.nickname }}
 | 
			
		||||
            <el-tag type="info" size="small">{{ processInstance.startUser.deptName }}</el-tag>
 | 
			
		||||
          </el-form-item>
 | 
			
		||||
          <el-form-item label="审批建议" prop="reason">
 | 
			
		||||
            <el-input
 | 
			
		||||
              type="textarea"
 | 
			
		||||
              v-model="auditForms[index].reason"
 | 
			
		||||
              placeholder="请输入审批建议"
 | 
			
		||||
            />
 | 
			
		||||
          </el-form-item>
 | 
			
		||||
        </el-form>
 | 
			
		||||
        <div style="margin-left: 10%; margin-bottom: 20px; font-size: 14px">
 | 
			
		||||
          <el-button type="success" @click="handleAudit(item, true)">
 | 
			
		||||
            <Icon icon="ep:select" /> 通过
 | 
			
		||||
          </el-button>
 | 
			
		||||
          <el-button type="danger" @click="handleAudit(item, false)">
 | 
			
		||||
            <Icon icon="ep:close" /> 不通过
 | 
			
		||||
          </el-button>
 | 
			
		||||
          <el-button type="primary" @click="openTaskUpdateAssigneeForm(item.id)">
 | 
			
		||||
            <Icon icon="ep:edit" /> 转办
 | 
			
		||||
          </el-button>
 | 
			
		||||
          <el-button type="primary" @click="handleDelegate(item)">
 | 
			
		||||
            <Icon icon="ep:position" /> 委派
 | 
			
		||||
          </el-button>
 | 
			
		||||
          <el-button type="warning" @click="handleBack(item)">
 | 
			
		||||
            <Icon icon="ep:back" /> 退回
 | 
			
		||||
          </el-button>
 | 
			
		||||
        </div>
 | 
			
		||||
      </el-col>
 | 
			
		||||
    </el-card>
 | 
			
		||||
 | 
			
		||||
    <!-- 申请信息 -->
 | 
			
		||||
    <el-card class="box-card" v-loading="processInstanceLoading">
 | 
			
		||||
      <template #header>
 | 
			
		||||
        <span class="el-icon-document">申请信息【{{ processInstance.name }}】</span>
 | 
			
		||||
      </template>
 | 
			
		||||
      <!-- 情况一:流程表单 -->
 | 
			
		||||
      <el-col v-if="processInstance?.processDefinition?.formType === 10" :span="16" :offset="6">
 | 
			
		||||
        <form-create
 | 
			
		||||
          ref="fApi"
 | 
			
		||||
          :rule="detailForm.rule"
 | 
			
		||||
          :option="detailForm.option"
 | 
			
		||||
          v-model="detailForm.value"
 | 
			
		||||
        />
 | 
			
		||||
      </el-col>
 | 
			
		||||
      <!-- 情况二:流程表单 -->
 | 
			
		||||
      <div v-if="processInstance?.processDefinition?.formType === 20">
 | 
			
		||||
        <router-link
 | 
			
		||||
          :to="
 | 
			
		||||
            processInstance.processDefinition.formCustomViewPath +
 | 
			
		||||
            '?id=' +
 | 
			
		||||
            processInstance.businessKey
 | 
			
		||||
          "
 | 
			
		||||
        >
 | 
			
		||||
          <el-button type="primary"><Icon icon="ep:view" /> 点击查看</el-button>
 | 
			
		||||
        </router-link>
 | 
			
		||||
      </div>
 | 
			
		||||
    </el-card>
 | 
			
		||||
 | 
			
		||||
    <!-- 审批记录 -->
 | 
			
		||||
    <ProcessInstanceTaskList :loading="tasksLoad" :tasks="tasks" />
 | 
			
		||||
 | 
			
		||||
    <!-- 高亮流程图 -->
 | 
			
		||||
    <ProcessInstanceBpmnViewer
 | 
			
		||||
      :id="id"
 | 
			
		||||
      :process-instance="processInstance"
 | 
			
		||||
      :loading="processInstanceLoading"
 | 
			
		||||
      :tasks="tasks"
 | 
			
		||||
      :bpmn-xml="bpmnXML"
 | 
			
		||||
    />
 | 
			
		||||
 | 
			
		||||
    <!-- 弹窗:转派审批人 -->
 | 
			
		||||
    <TaskUpdateAssigneeForm ref="taskUpdateAssigneeFormRef" @success="getDetail" />
 | 
			
		||||
  </ContentWrap>
 | 
			
		||||
</template>
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { useUserStore } from '@/store/modules/user'
 | 
			
		||||
import { setConfAndFields2 } from '@/utils/formCreate'
 | 
			
		||||
import type { ApiAttrs } from '@form-create/element-ui/types/config'
 | 
			
		||||
import * as DefinitionApi from '@/api/bpm/definition'
 | 
			
		||||
import * as ProcessInstanceApi from '@/api/bpm/processInstance'
 | 
			
		||||
import * as TaskApi from '@/api/bpm/task'
 | 
			
		||||
import TaskUpdateAssigneeForm from './TaskUpdateAssigneeForm.vue'
 | 
			
		||||
import ProcessInstanceBpmnViewer from './ProcessInstanceBpmnViewer.vue'
 | 
			
		||||
import ProcessInstanceTaskList from './ProcessInstanceTaskList.vue'
 | 
			
		||||
const { query } = useRoute() // 查询参数
 | 
			
		||||
const message = useMessage() // 消息弹窗
 | 
			
		||||
const { proxy } = getCurrentInstance() as any
 | 
			
		||||
 | 
			
		||||
const userId = useUserStore().getUser.id // 当前登录的编号
 | 
			
		||||
const id = query.id as unknown as number // 流程实例的编号
 | 
			
		||||
const processInstanceLoading = ref(false) // 流程实例的加载中
 | 
			
		||||
const processInstance = ref<any>({}) // 流程实例
 | 
			
		||||
const bpmnXML = ref('') // BPMN XML
 | 
			
		||||
const tasksLoad = ref(true) // 任务的加载中
 | 
			
		||||
const tasks = ref<any[]>([]) // 任务列表
 | 
			
		||||
// ========== 审批信息 ==========
 | 
			
		||||
const runningTasks = ref<any[]>([]) // 运行中的任务
 | 
			
		||||
const auditForms = ref<any[]>([]) // 审批任务的表单
 | 
			
		||||
const auditRule = reactive({
 | 
			
		||||
  reason: [{ required: true, message: '审批建议不能为空', trigger: 'blur' }]
 | 
			
		||||
})
 | 
			
		||||
// ========== 申请信息 ==========
 | 
			
		||||
const fApi = ref<ApiAttrs>() //
 | 
			
		||||
const detailForm = ref({
 | 
			
		||||
  // 流程表单详情
 | 
			
		||||
  rule: [],
 | 
			
		||||
  option: {},
 | 
			
		||||
  value: {}
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
/** 处理审批通过和不通过的操作 */
 | 
			
		||||
const handleAudit = async (task, pass) => {
 | 
			
		||||
  // 1.1 获得对应表单
 | 
			
		||||
  const index = runningTasks.value.indexOf(task)
 | 
			
		||||
  const auditFormRef = proxy.$refs['form' + index][0]
 | 
			
		||||
  // 1.2 校验表单
 | 
			
		||||
  const elForm = unref(auditFormRef)
 | 
			
		||||
  if (!elForm) return
 | 
			
		||||
  const valid = await elForm.validate()
 | 
			
		||||
  if (!valid) return
 | 
			
		||||
 | 
			
		||||
  // 2.1 提交审批
 | 
			
		||||
  const data = {
 | 
			
		||||
    id: task.id,
 | 
			
		||||
    reason: auditForms.value[index].reason
 | 
			
		||||
  }
 | 
			
		||||
  if (pass) {
 | 
			
		||||
    await TaskApi.approveTask(data)
 | 
			
		||||
    message.success('审批通过成功')
 | 
			
		||||
  } else {
 | 
			
		||||
    await TaskApi.rejectTask(data)
 | 
			
		||||
    message.success('审批不通过成功')
 | 
			
		||||
  }
 | 
			
		||||
  // 2.2 加载最新数据
 | 
			
		||||
  getDetail()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 转派审批人 */
 | 
			
		||||
const taskUpdateAssigneeFormRef = ref()
 | 
			
		||||
const openTaskUpdateAssigneeForm = (id: string) => {
 | 
			
		||||
  taskUpdateAssigneeFormRef.value.open(id)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 处理审批退回的操作 */
 | 
			
		||||
const handleDelegate = async (task) => {
 | 
			
		||||
  message.error('暂不支持【委派】功能,可以使用【转派】替代!')
 | 
			
		||||
  console.log(task)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 处理审批退回的操作 */
 | 
			
		||||
const handleBack = async (task) => {
 | 
			
		||||
  message.error('暂不支持【退回】功能!')
 | 
			
		||||
  console.log(task)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 获得详情 */
 | 
			
		||||
const getDetail = () => {
 | 
			
		||||
  // 1. 获得流程实例相关
 | 
			
		||||
  getProcessInstance()
 | 
			
		||||
  // 2. 获得流程任务列表(审批记录)
 | 
			
		||||
  getTaskList()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 加载流程实例 */
 | 
			
		||||
const getProcessInstance = async () => {
 | 
			
		||||
  try {
 | 
			
		||||
    processInstanceLoading.value = true
 | 
			
		||||
    const data = await ProcessInstanceApi.getProcessInstanceApi(id)
 | 
			
		||||
    if (!data) {
 | 
			
		||||
      message.error('查询不到流程信息!')
 | 
			
		||||
      return
 | 
			
		||||
    }
 | 
			
		||||
    processInstance.value = data
 | 
			
		||||
 | 
			
		||||
    // 设置表单信息
 | 
			
		||||
    const processDefinition = data.processDefinition
 | 
			
		||||
    if (processDefinition.formType === 10) {
 | 
			
		||||
      setConfAndFields2(
 | 
			
		||||
        detailForm,
 | 
			
		||||
        processDefinition.formConf,
 | 
			
		||||
        processDefinition.formFields,
 | 
			
		||||
        data.formVariables
 | 
			
		||||
      )
 | 
			
		||||
      nextTick().then(() => {
 | 
			
		||||
        fApi.value?.fapi?.btn.show(false)
 | 
			
		||||
        fApi.value?.fapi?.resetBtn.show(false)
 | 
			
		||||
        fApi.value?.fapi?.disabled(true)
 | 
			
		||||
      })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 加载流程图
 | 
			
		||||
    bpmnXML.value = await DefinitionApi.getProcessDefinitionBpmnXML(processDefinition.id)
 | 
			
		||||
  } finally {
 | 
			
		||||
    processInstanceLoading.value = false
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 加载任务列表 */
 | 
			
		||||
const getTaskList = async () => {
 | 
			
		||||
  try {
 | 
			
		||||
    // 获得未取消的任务
 | 
			
		||||
    tasksLoad.value = true
 | 
			
		||||
    const data = await TaskApi.getTaskListByProcessInstanceId(id)
 | 
			
		||||
    tasks.value = []
 | 
			
		||||
    // 1.1 移除已取消的审批
 | 
			
		||||
    data.forEach((task) => {
 | 
			
		||||
      if (task.result !== 4) {
 | 
			
		||||
        tasks.value.push(task)
 | 
			
		||||
      }
 | 
			
		||||
    })
 | 
			
		||||
    // 1.2 排序,将未完成的排在前面,已完成的排在后面;
 | 
			
		||||
    tasks.value.sort((a, b) => {
 | 
			
		||||
      // 有已完成的情况,按照完成时间倒序
 | 
			
		||||
      if (a.endTime && b.endTime) {
 | 
			
		||||
        return b.endTime - a.endTime
 | 
			
		||||
      } else if (a.endTime) {
 | 
			
		||||
        return 1
 | 
			
		||||
      } else if (b.endTime) {
 | 
			
		||||
        return -1
 | 
			
		||||
        // 都是未完成,按照创建时间倒序
 | 
			
		||||
      } else {
 | 
			
		||||
        return b.createTime - a.createTime
 | 
			
		||||
      }
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
    // 获得需要自己审批的任务
 | 
			
		||||
    runningTasks.value = []
 | 
			
		||||
    auditForms.value = []
 | 
			
		||||
    tasks.value.forEach((task) => {
 | 
			
		||||
      // 2.1 只有待处理才需要
 | 
			
		||||
      if (task.result !== 1) {
 | 
			
		||||
        return
 | 
			
		||||
      }
 | 
			
		||||
      // 2.2 自己不是处理人
 | 
			
		||||
      if (!task.assigneeUser || task.assigneeUser.id !== userId) {
 | 
			
		||||
        return
 | 
			
		||||
      }
 | 
			
		||||
      // 2.3 添加到处理任务
 | 
			
		||||
      runningTasks.value.push({ ...task })
 | 
			
		||||
      auditForms.value.push({
 | 
			
		||||
        reason: ''
 | 
			
		||||
      })
 | 
			
		||||
    })
 | 
			
		||||
  } finally {
 | 
			
		||||
    tasksLoad.value = false
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 初始化 */
 | 
			
		||||
onMounted(() => {
 | 
			
		||||
  getDetail()
 | 
			
		||||
})
 | 
			
		||||
</script>
 | 
			
		||||
		Loading…
	
		Reference in New Issue