first commit

This commit is contained in:
ye1023
2026-04-09 15:09:34 +08:00
commit d8e3a63df1
2246 changed files with 352109 additions and 0 deletions
@@ -0,0 +1,44 @@
<template>
<!--流程图弹窗-->
<BasicModal v-bind="$attrs" :bodyStyle="bodyStyle" :width="900" destroyOnClose :footer="null" @register="registerModal" title="流程图">
<BpmGraphic :instanceId="procInsId"></BpmGraphic>
</BasicModal>
</template>
<script lang="ts" setup>
import { ref, computed, unref, reactive, toRaw } from 'vue';
import { BasicModal, useModalInner } from '/src/components/Modal';
import BpmGraphic from '/src/views/super/bpm/process/components/BpmGraphic.vue';
import { useMessage } from '/@/hooks/web/useMessage';
import { getProcessInfo } from './bpm.api';
// Emits声明
const emit = defineEmits(['register']);
// 提示声明
const $message = useMessage();
// 流程实例id
const procInsId = ref('');
//样式
const bodyStyle = {
'overflow-y': 'auto',
'overflow-x': 'auto',
};
//表单赋值
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (params) => {
//初始化数据
await initData(params);
});
/**
* 初始化流程数据
* @param params
*/
async function initData(params) {
let res = await getProcessInfo(params);
if (res.success) {
procInsId.value = res.result.processInstanceId;
} else {
$message.warning(res.message);
}
}
</script>
@@ -0,0 +1,126 @@
<template>
<!-- 历史流程任务处理弹出框 -->
<a-modal
width="80%"
style="top: 20px"
destroyOnClose
:title="data.title"
v-model:open="data.visible"
:bodyStyle="data.bodyStyle"
:footer="null"
@cancel="handleModalCancel"
>
<a-tabs defaultActiveKey="1" tabPosition="left">
<a-tab-pane key="1">
<template #tab>
<Icon icon="ant-design:file-text-outlined" />
<span>附加单据</span>
</template>
<div class="component_div">
<template v-if="data.compType == 'comp'">
<DynamicLink :path="path" :formData="formData"></DynamicLink>
</template>
<template v-else-if="data.compType == 'iframe'">
<iframe :src="data.iframeUrl" frameborder="0" width="100%" :height="data.height" scrolling="auto"></iframe>
</template>
</div>
</a-tab-pane>
<a-tab-pane key="2">
<template #tab>
<Icon icon="ant-design:file-text-outlined" />
<span>审批记录</span>
</template>
<HisTaskModule :formData="formData"></HisTaskModule>
</a-tab-pane>
<a-tab-pane key="3">
<template #tab>
<Icon icon="ant-design:sliders-outlined" />
<span>流程跟踪</span>
</template>
<ProcessDiagram :formData="formData"></ProcessDiagram>
</a-tab-pane>
</a-tabs>
</a-modal>
</template>
<script lang="ts" setup>
import { computed, ref, unref, reactive } from 'vue';
import {getBpmFormUrl, isUrl} from '/@/utils/is';
import { getToken } from '/@/utils/auth';
import { useGlobSetting } from '/@/hooks/setting';
import DynamicLink from './DynamicLink.vue';
import ProcessDiagram from './ProcessDiagram.vue';
import HisTaskModule from './HisTaskModule.vue';
import { getBizHisProcessNodeInfo } from './bpm.api';
const { domainUrl } = useGlobSetting();
//数据
const data = reactive({
loading: false,
title: '流程',
visible: false,
bodyStyle: {
padding: '0',
height: window.innerHeight - 80 + 'px',
'overflow-y': 'auto',
},
height: window.innerHeight - 120 + 'px',
iframeUrl: '',
compType: '',
});
const formData = ref({});
const path = ref('');
/**
* 关闭弹窗
*/
function handleModalCancel() {
data.visible = false;
}
/**
* 打开弹窗前处理
* @param record
*/
async function handleTrack(params) {
let res = await getBizHisProcessNodeInfo(params);
if (res.success) {
console.log('获取流程节点信息', res);
formData.value = {
dataId: res.result.dataId,
procInsId: res.result.procInsId,
tableName: res.result.tableName,
vars: res.result.records,
};
console.log('------获取流程节点信息', unref(formData));
path.value = res.result.formUrl;
console.log('获取流程节点信息', path);
let TOKEN = getToken();
let DOMAIN_URL = domainUrl;
let TASKID = unref(formData).taskDefKey;
//let URL = (unref(path) || '').replace(/{{([^}}]+)?}}/g, (s1, s2) => eval(s2)); // URL支持{{ window.xxx }}占位符变量
//获取流程审批url
let URL = getBpmFormUrl(unref(path), TOKEN, DOMAIN_URL, TASKID);
if (isUrl(URL)) {
data.iframeUrl = URL;
data.compType = 'iframe';
} else {
data.compType = 'comp';
}
data.visible = true;
}
}
defineExpose({
handleTrack,
data,
});
</script>
<style lang="less" scoped>
.ant-tabs-left-content {
padding-top: 10px !important;
}
</style>
@@ -0,0 +1,59 @@
<template>
<!--委派弹窗-->
<BasicModal
v-bind="$attrs"
@register="registerModal"
destroyOnClose
:bodyStyle="{ minHeight: '100px', maxHeight: '100px' }"
:title="title"
@ok="handleSubmit"
:width="700"
>
<BasicForm @register="registerForm" />
</BasicModal>
</template>
<script lang="ts" setup>
import { ref, computed, unref } from 'vue';
import { BasicModal, useModalInner } from '/@/components/Modal';
import { BasicForm, useForm } from '/@/components/Form/index';
import { delegateFormSchema } from './bpm.data';
// 声明Emits
const emit = defineEmits(['success', 'register']);
//组件接受传参
const props = defineProps({
title: { type: String, default: '请选择委托人', required: false },
});
//表单配置
const [registerForm, { resetFields, validate }] = useForm({
labelWidth: 90,
schemas: delegateFormSchema,
showActionButtonGroup: false,
});
//表单赋值
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
await resetFields();
});
//表单提交事件
async function handleSubmit() {
try {
const values = await validate();
setModalProps({ confirmLoading: true });
//关闭弹窗
closeModal();
//刷新列表
emit('success', values);
} finally {
setModalProps({ confirmLoading: false });
}
}
</script>
<style scoped>
/*update-begin---author:wangshuai ---date:20230703 for:【QQYUN-5685】3、租户角色下,查询居左显示*/
:deep(.ant-form-item-control-input-content){
text-align: left;
}
/*update-end---author:wangshuai ---date:20230703 for:【QQYUN-5685】3、租户角色下,查询居左显示*/
</style>
@@ -0,0 +1,55 @@
<template>
<div>
<Suspense v-if="comp">
<template #default>
<component :is="comp" :formData="formData" v-if="comp" form-bpm></component>
</template>
<template #fallback>
<div style="width: 100%; text-align: center; padding-top: 60px">
<a-spin spinning tip="表单加载中..." />
</div>
</template>
</Suspense>
<div v-else>表单地址不存在</div>
</div>
</template>
<script lang="ts" setup>
import { defineAsyncComponent, computed, markRaw } from 'vue';
import { importViewsFile } from '/@/utils';
//组件接受传参
const props = defineProps({
path: { type: String },
formData: { type: Object },
});
// 表单地址兼容vue2
const FORM_PATH_MAP = {
'modules/bpm/task/form/OnlineFormDetail': 'super/bpm/process/components/OnlineFormDetail',
'modules/bpm/task/form/OnlineFormOpt': 'super/bpm/process/components/OnlineFormOpt',
//借款申请表单
'modules/extbpm/joa/modules/JoaLoanApplyForm': 'super/bpm/example/joa/loan/components/LoanApplyForm',
//借款表单
'modules/extbpm/joa/modules/JoaLoanForm': 'super/bpm/example/joa/loan/components/LoanForm',
//出差表单
'modules/extbpm/joa/modules/JoaBusinesStripForm': 'super/bpm/example/joa/businessTrip/components/BusinessTripForm',
//请假表单
'modules/extbpm/joa/modules/JoaEmployeeLeaveForm': 'super/bpm/example/joa/leave/components/LeaveForm',
//公文表单
'modules/extbpm/joa/modules/JoaDocSendingForm': 'super/bpm/example/joa/docSend/components/DocSendForm',
//批量请假单
'modules/extbpm/biz/modules/ExtBizLeaveForm': 'super/bpm/example/batch/components/BizLeaveForm',
};
//组件路径
/**
* 获取组件
* @type {ComputedRef<function(): *>}
*/
const comp = computed(() => {
let temp = props.path;
if (FORM_PATH_MAP[temp]) {
temp = FORM_PATH_MAP[temp];
}
console.log('bpm组件名称:', temp);
console.log('bpm组件数据:', props.formData);
return defineAsyncComponent(() => importViewsFile(temp));
});
</script>
@@ -0,0 +1,126 @@
<template>
<!-- 历史流程任务处理弹出框 -->
<a-modal
width="100%"
style="top: 0"
wrapClassName="full-modal"
destroyOnClose
:title="data.title"
v-model:open="data.visible"
:bodyStyle="data.bodyStyle"
:footer="null"
@cancel="handleModalCancel"
>
<a-tabs defaultActiveKey="1" tabPosition="left">
<a-tab-pane key="1">
<template #tab>
<Icon icon="ant-design:file-text-outlined" />
<span>附加单据</span>
</template>
<div class="component_div">
<template v-if="isComp">
<DynamicLink v-if="path" :path="path" :formData="formData"></DynamicLink>
<div v-else>表单地址不存在</div>
</template>
<template v-else>
<iframe :src="data.iframeUrl" frameborder="0" width="100%" :height="data.height" scrolling="auto"></iframe>
</template>
</div>
</a-tab-pane>
<a-tab-pane key="2">
<template #tab>
<Icon icon="ant-design:user-outlined" />
<span>任务处理</span>
</template>
<HisTaskModule :formData="formData"></HisTaskModule>
</a-tab-pane>
<a-tab-pane key="3">
<template #tab>
<Icon icon="ant-design:sliders-outlined" />
<span>流程图</span>
</template>
<ProcessDiagram :formData="formData"></ProcessDiagram>
</a-tab-pane>
</a-tabs>
</a-modal>
</template>
<script lang="ts" setup>
import { computed, reactive } from 'vue';
import { getBpmFormUrl, isUrl} from '/@/utils/is';
import { getToken } from '/@/utils/auth';
import { useGlobSetting } from '/@/hooks/setting';
import DynamicLink from './DynamicLink.vue';
import ProcessDiagram from './ProcessDiagram.vue';
import HisTaskModule from './HisTaskModule.vue';
const globSetting = useGlobSetting();
//组件接受传参
const props = defineProps({
path: { type: String },
formData: { type: Object },
});
//数据
const data = reactive({
loading: false,
title: '流程',
visible: false,
bodyStyle: {
padding: '0',
height: window.innerHeight - 80 + 'px',
'overflow-y': 'auto',
},
height: window.innerHeight - 120 + 'px',
iframeUrl: '',
});
let TOKEN = getToken();
let DOMAIN_URL = globSetting.domainUrl;
let TASKID = props?.formData?.taskDefKey;
//是否组件
const isComp = computed(() => {
//获取流程审批url
//let URL = (props.path || '').replace(/{{([^}}]+)?}}/g, (s1, s2) => eval(s2)); // URL支持{{ window.xxx }}占位符变量
let URL = getBpmFormUrl(props.path, TOKEN, DOMAIN_URL, TASKID);
if (isUrl(URL)) {
data.iframeUrl = URL;
return false;
}
return true;
});
/**
* 关闭弹窗
*/
function handleModalCancel() {
data.visible = false;
}
/**
* 打开弹窗前处理
* @param record
*/
function deal(record) {
data.visible = true;
}
defineExpose({
deal,
data,
});
</script>
<style lang="less" scoped>
.component_div {
margin-top: 5px;
margin-bottom: 5px;
}
:deep(.ant-modal) {
top: 0;
padding: 0;
}
</style>
@@ -0,0 +1,202 @@
<template>
<!--流程任务历史-->
<div>
<!-- 步骤条 -->
<a-spin :spinning="loading">
<a-card>
<a-steps progressDot :current="stepIndex" style="padding: 10px" size="default">
<template v-if="resultObj.bpmLogListCount > 3">
<a-step>
<template #title>
<div class="task-title">...</div>
</template>
</a-step>
</template>
<template v-for="(item, index) in resultObj.bpmLogStepList">
<a-step>
<template #title>
<div class="task-title">{{ item.taskName }}</div>
</template>
<template #description>
<div class="descriptionDiv">
<span>
<a-avatar shape="square" style="background-color: #40a9ff">
<template #icon><UserOutlined /></template>
</a-avatar>
</span>
<span style="margin-left: 5px">
<div class="task-date" style="text-align: left">
<a-tooltip placement="top">
<template #title
><span>{{ item.opTime }}</span></template
>
<span> {{ item.opTime ? item.opTime.substr(0, 10) : item.opTime }}</span>
</a-tooltip>
</div>
<div class="task-user" style="text-align: left"
><span> {{ item.opUserName }}</span></div
>
</span>
</div>
</template>
</a-step>
</template>
<template v-if="resultObj.currTaskName && resultObj.currTaskName != ''">
<a-step>
<template #title>
<div class="task-title">{{ resultObj.currTaskName }}</div>
</template>
<template #description>
<div class="descriptionDiv">
<a-avatar style="background-color: #faad14eb">
<template #icon><UserOutlined /></template>
</a-avatar>
<span style="margin-left: 5px">
<div class="task-date" style="text-align: left">
<a-tooltip placement="top">
<template #title
><span>{{ resultObj.currTaskNameStartTime }}</span></template
>
<span style="color: #ff6d75">
{{
resultObj.currTaskNameStartTime ? resultObj.currTaskNameStartTime.substr(0, 10) : resultObj.currTaskNameStartTime
}}</span
>
</a-tooltip>
</div>
<div class="task-user" style="text-align: left"
><span> {{ resultObj.currTaskNameAssignee }}</span></div
>
</span>
</div>
</template>
</a-step>
<a-step>
<template #title>
<div class="task-title">...</div>
</template>
</a-step>
</template>
</a-steps>
</a-card>
<!-- 意见 -->
<a-card title="意见信息" :bodyStyle="{ padding: '0 20px' }" size="default" style="margin-top: 20px">
<a-list itemLayout="vertical">
<template v-for="(item, index) in resultObj.bpmLogList">
<a-list-item>
<a-list-item-meta :description="item.remarks||'无意见信息'">
<template #title>
<a
><p>{{ item.opUserName }}</p
><span style="color: #ff6d75">[{{ item.taskName }}]</span> {{ item.opTime }}</a
>
</template>
<template #avatar>
<a-avatar :size="36" style="background-color: #51cbff">
<template #icon><UserOutlined /></template>
</a-avatar>
</template>
</a-list-item-meta>
<template v-for="(file, index) in item.bpmFiles" :key="index">
<div class="ant-upload-list ant-upload-list-text">
<div class="ant-upload-list-item ant-upload-list-item-done">
<div class="ant-upload-list-item-info">
<span>
<PaperClipOutlined />
<a
target="_blank"
rel="noopener noreferrer"
:title="file.fileName"
:href="getFileAccessHttpUrl(file.filePath)"
class="ant-upload-list-item-name"
>{{ file.fileName }}</a
>
</span>
</div>
</div>
</div>
</template>
</a-list-item>
</template>
</a-list>
</a-card>
</a-spin>
</div>
</template>
<script lang="ts" setup>
import { ref, unref, onMounted, computed } from 'vue';
import JEllipsis from '/@/components/Form/src/jeecg/components/JEllipsis.vue';
import { getFileAccessHttpUrl } from '/@/utils/common/compUtils';
import { getHisProcessTaskTransInfo } from './bpm.api';
import { UserOutlined, PaperClipOutlined } from '@ant-design/icons-vue';
//组件接受传参
const props = defineProps({
formData: { type: Object },
});
//组件接受传参
const resultObj = ref({});
const loading = ref(false);
//步骤点
const stepIndex = computed(() => {
if (unref(resultObj).bpmLogListCount > 3) {
return unref(resultObj).bpmLogStepListCount + 1;
}
return unref(resultObj).bpmLogStepListCount;
});
/**
* 加载数据
* @param formData
*/
async function loadData(formData) {
var params = { procInstId: formData.procInsId }; //查询条件
loading.value = true;
const res = await getHisProcessTaskTransInfo(params);
loading.value = false;
if (res.success) {
resultObj.value = res.result;
}
}
onMounted(() => {
loadData(props.formData);
});
</script>
<style scoped>
.task-info {
margin: 20px 0;
}
.task-title {
font-weight: bold;
}
.task-date {
text-overflow: ellipsis;
white-space: nowrap;
}
.ant-steps-item-description {
max-width: 200px !important;
}
/** Button按钮间距 */
.ant-btn {
margin-left: 3px;
}
/** 标题和描述对齐 */
:deep(.ant-steps-item-content) {
text-align: left;
margin-left: 50px;
}
/** 描述的样式 */
.descriptionDiv {
display: flex;
justify-content: left;
align-items: center;
margin-top: 5px;
}
</style>
@@ -0,0 +1,133 @@
<template>
<div>
<div class="graphic">
<!--流程图 -->
<BpmGraphic :instanceId="formData.procInsId" @task="getTaskList"></BpmGraphic>
</div>
<a-card title="流程历史跟踪">
<a-table rowKey="taskId" :loading="loading" :dataSource="dataSource" :columns="columns" size="small">
<!-- 字符串超长截取省略号显示-->
<template #remarks="{ record }">
<JEllipsis :value="getNodeInfo(record)" :length="25" />
</template>
</a-table>
</a-card>
</div>
</template>
<script lang="ts" setup>
import { ref, unref, onMounted } from 'vue';
import { useMessage } from '/@/hooks/web/useMessage';
import JEllipsis from '/@/components/Form/src/jeecg/components/JEllipsis.vue';
import BpmGraphic from '/@/views/super/bpm/process/components/BpmGraphic.vue';
import { getProcessHistoryList } from './bpm.api';
//组件接受传参
const props = defineProps({
formData: { type: Object },
});
//提示
const { createMessage } = useMessage();
const loading = ref(false);
//列表数据
const dataSource = ref([]);
const taskList = ref([]);
// 查询数据
async function loadData() {
loading.value = true;
let params = { processInstanceId: props.formData.procInsId };
const res = await getProcessHistoryList(params);
loading.value = false;
if (res.success) {
dataSource.value = res.result.records;
} else {
createMessage.warning('加载失败');
}
}
function getTaskList(result) {
taskList.value = result;
}
/**
* 获取节点备注信息
* @param record
*/
function getNodeInfo(record) {
let arr = taskList.value;
if (arr && arr.length > 0) {
for (let item of arr) {
if (item.id == record.id) {
return item.remarks;
}
}
}
return '';
}
onMounted(() => {
taskList.value = [];
loadData();
});
//定义列
const columns = [
{
title: '#',
dataIndex: '#',
width: 40,
customRender: ({ text, index }) => {
return parseInt(index) + 1;
},
},
{
title: '名称',
dataIndex: 'name',
customRender: ({ text }) => {
if (text == 'start1') {
return '开始';
} else if (text == 'end') {
return '结束';
} else {
return text;
}
},
},
{
title: '流程实例ID',
dataIndex: 'processInstanceId',
},
{
title: '开始时间',
dataIndex: 'startTime',
},
{
title: '结束时间',
dataIndex: 'endTime',
},
{
title: '负责人',
dataIndex: 'assigneeName',
},
{
title: '处理结果',
dataIndex: 'deleteReason',
},
{
title: '处理意见',
fixed: 'right',
width: 350,
dataIndex: 'remarks',
slots: { customRender: 'remarks' },
},
];
</script>
<style lang="less" scoped>
.graphic {
margin-bottom: 20px;
height: 400px;
overflow: hidden;
overflow-y: auto;
overflow-x: auto;
}
</style>
@@ -0,0 +1,53 @@
<!--选择跳转节点弹窗-->
<template>
<BasicModal
v-bind="$attrs"
@register="registerModal"
destroyOnClose
:bodyStyle="{ minHeight: '100px', maxHeight: '100px' }"
title="选择跳转节点"
@ok="handleSubmit"
:width="700"
>
<BasicForm @register="registerForm" />
</BasicModal>
</template>
<script lang="ts" setup>
import { ref, computed, unref } from 'vue';
import { BasicModal, useModalInner } from '/@/components/Modal';
import { BasicForm, useForm } from '/@/components/Form/index';
import { skipNode } from './bpm.api';
import { taskNodeFormSchema } from './bpm.data';
// 声明Emits
const emit = defineEmits(['success', 'register']);
//表单配置
const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({
labelWidth: 150,
schemas: taskNodeFormSchema,
showActionButtonGroup: false,
});
//表单赋值
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
await resetFields();
setModalProps({ confirmLoading: false });
await setFieldsValue({
...data,
});
});
//表单提交事件
async function handleSubmit() {
try {
const values = await validate();
setModalProps({ confirmLoading: true });
//提交跳转
await skipNode(values);
//关闭弹窗
closeModal();
//刷新列表
emit('success');
} finally {
setModalProps({ confirmLoading: false });
}
}
</script>
@@ -0,0 +1,133 @@
import { defHttp } from '/@/utils/http/axios';
enum Api {
hisProcessNodeInfo = '/act/process/extActProcessNode/getHisProcessNodeInfo',
processHistoryList = '/act/task/processHistoryList',
hisProcessTaskTransInfo = '/act/task/getHisProcessTaskTransInfo',
skipNode = '/act/processInstance/skipNode',
taskEntrust = '/act/task/taskEntrust',
getAllTask = '/act/processInstance/getAllTask',
reassign = '/act/processInstance/reassign',
bizHisProcessNodeInfo = '/act/process/extActProcessNode/getBizHisProcessNodeInfo',
getNotifyList = '/act/process/extActTaskNotification/mylist',
notifyMeList = '/act/process/extActTaskNotification/list',
taskNotification = '/act/process/extActTaskNotification/taskNotification',
getBizProcessNodeInfo = '/act/process/extActProcessNode/getBizProcessNodeInfo',
getProcessTaskTransInfo = '/act/task/getProcessTaskTransInfo',
processComplete = '/act/task/processComplete',
suspend = '/act/processInstance/suspend',
restart = '/act/processInstance/restart',
claim = '/act/task/claim',
getProcessInfo = '/act/process/extActFlowData/getProcessInfo',
}
/**
* 获取流程节点历史信息
* @param params
*/
export const hisProcessNodeInfo = (params) => {
return defHttp.get({ url: Api.hisProcessNodeInfo, params }, { isTransformResponse: false });
};
/**
* 获取流程历史信息
* @param params
*/
export const getProcessHistoryList = (params) => defHttp.get({ url: Api.processHistoryList, params }, { isTransformResponse: false });
/**
* 获取流程历史流转信息
* @param params
*/
export const getHisProcessTaskTransInfo = (params) => defHttp.get({ url: Api.hisProcessTaskTransInfo, params }, { isTransformResponse: false });
/**
* 委派
* @param params
*/
export const taskEntrust = (params, handleSuccess?) => {
return defHttp.put({ url: Api.taskEntrust, params }, { isTransformResponse: false }).then((res) => {
handleSuccess && handleSuccess(res);
});
};
/**
* 获取所有任务节点
* @param params
*/
export const getAllTask = (params) => defHttp.get({ url: Api.getAllTask, params });
/**
* 跳转节点
* @param params
*/
export const skipNode = (params) => defHttp.get({ url: Api.skipNode, params });
/**
* 获取业务流程节点信息
* @param params
*/
export const getBizHisProcessNodeInfo = (params) => defHttp.get({ url: Api.bizHisProcessNodeInfo, params }, { isTransformResponse: false });
/**
* 获取我催办的流程列表
* @param params
*/
export const getNotifyList = (params) => defHttp.get({ url: Api.getNotifyList, params });
/**
* 获取催办我的流程列表
* @param params
*/
export const getNotifyMeList = (params) => defHttp.get({ url: Api.notifyMeList, params });
/**
* 催办
* @param params
*/
export const saveOrUpdateNotify = (params) => {
return defHttp.post({ url: Api.taskNotification, params });
};
/**
* 获取业务流程节点信息
* @param params
*/
export const getBizProcessNodeInfo = (params) => {
return defHttp.get({ url: Api.getBizProcessNodeInfo, params }, { isTransformResponse: false });
};
/**
* 获取业务流转信息
* @param params
*/
export const getProcessTaskTransInfo = (params) => {
return defHttp.get({ url: Api.getProcessTaskTransInfo, params }, { isTransformResponse: false });
};
/**
* 流程办理
* @param params
*/
export const processComplete = (params) => {
return defHttp.post({ url: Api.processComplete, params }, { isTransformResponse: false });
};
/**
* 挂起
* @param params
*/
export const suspend = (params) => {
return defHttp.get({ url: Api.suspend, params }, { isTransformResponse: false });
};
/**
* 解挂
* @param params
*/
export const restart = (params) => {
return defHttp.get({ url: Api.restart, params }, { isTransformResponse: false });
};
/**
* 签收
* @param params
*/
export const claim = (params) => {
return defHttp.put({ url: Api.claim, params }, { isTransformResponse: false });
};
/**
* 获取流程信息
* @param params
*/
export const getProcessInfo = (params) => {
return defHttp.get({ url: Api.getProcessInfo, params }, { isTransformResponse: false });
};
@@ -0,0 +1,52 @@
import { FormSchema } from '/@/components/Table';
import { getAllTask } from './bpm.api';
/**
* 委派modal的form
*/
export const delegateFormSchema: FormSchema[] = [
{
field: 'username',
label: '用户名',
component: 'JSelectUserByDept',
required: true,
componentProps: {
labelKey: 'realname',
rowKey: 'username',
showButton: false,
isRadioSelection: true,
},
},
];
/**
* 跳转节点form
*/
export const taskNodeFormSchema: FormSchema[] = [
{
field: 'taskId',
label: '',
component: 'Input',
show: false,
},
{
field: 'skipTaskNode',
label: '跳转节点',
component: 'ApiSelect',
required: true,
componentProps: ({ formModel }) => {
return {
api: getAllTask,
params: { taskId: formModel.taskId },
labelField: 'name',
valueField: 'taskKey',
immediate: false,
onChange: (e) => {
console.log('selected:', e);
},
onOptionsChange: (options) => {
console.log('get options', options.length, options);
},
};
},
},
];
@@ -0,0 +1,51 @@
import { ref, unref } from 'vue';
import { hisProcessNodeInfo } from '../bpm.api';
import { getQueryVariable } from '/@/utils';
import { isUrl } from '/@/utils/is';
/**
*
* @param path 路径
* @param taskDealRef 弹窗示例
*/
export function useBpmNodeInfo(path, taskDealRef) {
const formData = ref({});
/**
* 获取流程历史节点信息
* @param record
*/
function getHisProcessNodeInfo(record) {
hisProcessNodeInfo({ procInstId: record.processInstanceId }).then((res) => {
console.log('获取流程节点信息', res);
if (res.success) {
let data = {
dataId: res.result.dataId,
taskId: record.id,
taskDefKey: record.taskId,
procInsId: record.processInstanceId,
tableName: res.result.tableName,
vars: res.result.records,
};
formData.value = data;
//update--begin--autor:scott-----date:20191005------for:流程节点配置组件URL的时候也支持传递参数了,解决TASK #3238流程节点无法与online的复制视图对接------
console.log('获取流程节点表单URL ', res.result.formUrl);
let tempFormUrl = res.result.formUrl;
//节点配置表单URL,VUE组件类型对应的拓展参数
if (tempFormUrl && tempFormUrl.indexOf('?') != -1 && !isUrl(tempFormUrl) && tempFormUrl.indexOf('{{DOMAIN_URL}}') == -1) {
tempFormUrl = res.result.formUrl.split('?')[0];
console.log('获取流程节点表单URL(去掉参数)', tempFormUrl);
formData.value['extendUrlParams'] = getQueryVariable(res.result.formUrl);
}
path.value = tempFormUrl;
//update--end--autor:scott-----date:20191005------for:流程节点配置组件URL的时候也支持传递参数了,解决TASK #3238流程节点无法与online的复制视图对接------
console.log('获取流程节点信息formData', unref(formData));
console.log('获取流程节点信息path', unref(path));
taskDealRef.value.deal(record);
taskDealRef.value.data.title = '流程历史';
console.log('taskDealRef', taskDealRef.value);
}
});
}
return { getHisProcessNodeInfo, formData };
}
@@ -0,0 +1,52 @@
<template>
<BasicModal v-bind="$attrs" @register="registerModal" :title="title" @ok="handleSubmit" :width="700" :min-height="300">
<BasicForm @register="registerForm" />
</BasicModal>
</template>
<script lang="ts" setup>
import { ref, computed, unref } from 'vue';
import { BasicModal, useModalInner } from '/@/components/Modal';
import { BasicForm, useForm } from '/@/components/Form/index';
import { formSchema } from '../expression.data';
import { saveOrUpdate } from '../expression.api';
// 声明Emits
const emit = defineEmits(['success', 'register']);
const isUpdate = ref(true);
//表单配置
const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({
// labelWidth: 150,
schemas: formSchema,
showActionButtonGroup: false,
});
//表单赋值
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
//重置表单
await resetFields();
setModalProps({ confirmLoading: false });
isUpdate.value = !!data?.isUpdate;
if (unref(isUpdate)) {
//表单赋值
await setFieldsValue({
...data.record,
});
}
});
//设置标题
const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑'));
//表单提交事件
async function handleSubmit() {
try {
const values = await validate();
setModalProps({ confirmLoading: true });
//提交表单
await saveOrUpdate(values, isUpdate.value);
//关闭弹窗
closeModal();
//刷新列表
emit('success');
} finally {
setModalProps({ confirmLoading: false });
}
}
</script>
@@ -0,0 +1,50 @@
import { defHttp } from '/@/utils/http/axios';
import { Modal } from 'ant-design-vue';
enum Api {
list = '/act/process/extActExpression/list',
save = '/act/process/extActExpression/add',
edit = '/act/process/extActExpression/edit',
delete = '/act/process/extActExpression/delete',
deleteBatch = '/act/process/extActExpression/deleteBatch',
}
/**
* 列表
* @param params
*/
export const list = (params) => defHttp.get({ url: Api.list, params });
/**
* 保存或者更新
* @param params
*/
export const saveOrUpdate = (params, isUpdate) => {
let url = isUpdate ? Api.edit : Api.save;
return isUpdate ? defHttp.put({ url: url, params }) : defHttp.post({ url: url, params });
};
/**
* 删除监听
* @param params
*/
export const deleteOne = (params, handleSuccess) => {
return defHttp.delete({ url: Api.delete, data: params }, { joinParamsToUrl: true }).then(() => {
handleSuccess();
});
};
/**
* 批量删除
* @param params
*/
export const batchDelete = (params, handleSuccess) => {
Modal.confirm({
title: '确认删除',
content: '是否删除选中数据',
okText: '确认',
cancelText: '取消',
onOk: () => {
return defHttp.delete({ url: Api.deleteBatch, data: params }, { joinParamsToUrl: true }).then(() => {
handleSuccess();
});
},
});
};
@@ -0,0 +1,73 @@
import { FormSchema } from '/@/components/Table';
import {render} from "@/utils/common/renderUtils";
export const columns = [
{
title: '表达式名称',
dataIndex: 'name',
width: 180,
ellipsis: true,
},
{
title: '表达式',
width: 180,
dataIndex: 'expression',
},
{
title: '业务类型',
width: 180,
dataIndex: 'bizType',
customRender: ({ text }) => {
return render.renderDict(text, 'processExpressionBizType');
},
},
];
/**
* 列表查询form
*/
export const searchFormSchema: FormSchema[] = [
{
field: 'name',
label: '名称',
component: 'Input',
colProps: { span: 6 },
},
// {
// field: 'expression',
// label: '表达式',
// component: 'Input',
// colProps: { span: 6 },
// },
];
/**
* 表单form
*/
export const formSchema: FormSchema[] = [
{
field: 'id',
label: '',
component: 'Input',
show: false,
},
{
label: '表达式名称',
field: 'name',
required: true,
component: 'Input',
},
{
label: '表达式',
field: 'expression',
required: true,
component: 'InputTextArea',
},
{
label: '业务类型',
field: 'bizType',
required: false,
component: 'JDictSelectTag',
componentProps: {
dictCode: 'processExpressionBizType',
},
},
];
@@ -0,0 +1,117 @@
<template>
<div>
<BasicTable @register="registerTable" :rowSelection="rowSelection">
<template #tableTitle>
<a-button type="primary" preIcon="ant-design:plus-outlined" @click="handleCreate"> 新增</a-button>
<a-dropdown v-if="selectedRowKeys.length > 0">
<template #overlay>
<a-menu>
<a-menu-item key="1" @click="handleBatchDelete">
<Icon icon="ant-design:delete-outlined"></Icon>
删除
</a-menu-item>
</a-menu>
</template>
<a-button
>批量操作
<Icon icon="mdi:chevron-down"></Icon>
</a-button>
</a-dropdown>
</template>
<!--操作栏-->
<template #action="{ record }">
<TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)" />
</template>
</BasicTable>
<!--监听弹窗-->
<ExpressionModal @register="registerModal" @success="reload"></ExpressionModal>
</div>
</template>
<script lang="ts" name="process-expression-list" setup>
import { ref } from 'vue';
import { BasicTable, TableAction } from '/@/components/Table';
import ExpressionModal from './components/ExpressionModal.vue';
import { useModal } from '/@/components/Modal';
import { columns, searchFormSchema } from './expression.data';
import { list, deleteOne, batchDelete } from './expression.api';
import { useListPage } from '/@/hooks/system/useListPage';
//弹窗
const [registerModal, { openModal }] = useModal();
// 列表页面公共参数、方法
const { prefixCls, tableContext } = useListPage({
designScope: 'process-expression',
tableProps: {
title: '流程表达式',
api: list,
columns: columns,
formConfig: {
schemas: searchFormSchema,
},
actionColumn: {
width: 120,
fixed: 'right',
},
},
});
const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext;
/**
* 新增
*/
function handleCreate() {
openModal(true, {
isUpdate: false,
});
}
/**
* 编辑
*/
function handleEdit(record: Recordable) {
openModal(true, {
record,
isUpdate: true,
});
}
/**
* 删除
* @param id
*/
async function handleDelete(id) {
await deleteOne({ id }, reload);
}
/**
* 批量删除事件
*/
async function handleBatchDelete() {
await batchDelete({ ids: selectedRowKeys.value }, () => {
selectedRowKeys.value = [];
reload();
});
}
/**
* 操作栏
*/
function getTableAction(record) {
return [
{
label: '编辑',
onClick: handleEdit.bind(null, record),
},
];
}
/**
* 下拉操作栏
*/
function getDropDownAction(record) {
return [
{
label: '删除',
popConfirm: {
title: '是否确认删除',
confirm: handleDelete.bind(null, record.id),
},
},
];
}
</script>
@@ -0,0 +1,30 @@
import { defHttp } from '/@/utils/http/axios';
enum Api {
list = '/act/task/historyProcessList',
invalidProcess = '/act/task/invalidProcess',
callBackProcess = '/act/task/callBackProcess',
}
/**
* 列表
* @param params
*/
export const list = (params) => defHttp.get({ url: Api.list, params });
/**
* 作废流程
* @param params
*/
export const invalidProcess = (params, handleSuccess) => {
return defHttp.put({ url: Api.invalidProcess, params }).then(() => {
handleSuccess();
});
};
/**
* 取回流程
* @param params
*/
export const callBackProcess = (params, handleSuccess) => {
return defHttp.put({ url: Api.callBackProcess, params }).then(() => {
handleSuccess();
});
};
@@ -0,0 +1,77 @@
import { FormSchema } from '/@/components/Table';
export const columns = [
{
title: '业务标题',
dataIndex: 'bpmBizTitle',
width: 180,
ellipsis: true,
},
{
title: '流程名称',
dataIndex: 'prcocessDefinitionName',
},
{
title: '流程实例',
dataIndex: 'processInstanceId',
width: 180,
},
{
title: '发起人',
dataIndex: 'startUserName',
},
{
title: '开始日期',
dataIndex: 'startTime',
},
{
title: '流程编号',
dataIndex: 'processDefinitionId',
},
{
title: '结束时间',
dataIndex: 'endTime',
},
{
title: '耗时',
dataIndex: 'spendTimes',
},
{
title: '状态',
dataIndex: 'bpmStatus',
customRender: ({ text }) => {
switch (text) {
case '1':
return '待提交';
case '2':
return '处理中';
case '3':
return '已完成';
case 'rejectProcess':
return '已驳回';
case 'callBackProcess':
return '已取回';
case 'invalidProcess':
return '已作废';
}
return text;
},
},
];
/**
* 列表查询form
*/
export const searchFormSchema: FormSchema[] = [
{
field: 'processDefinitionId',
label: '流程编号',
component: 'Input',
colProps: { span: 6 },
},
{
field: 'processName',
label: '流程名称',
component: 'Input',
colProps: { span: 6 },
},
];
@@ -0,0 +1,123 @@
<template>
<div>
<BasicTable @register="registerTable" :rowSelection="rowSelection">
<!--操作栏-->
<template #action="{ record }">
<TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)" />
</template>
</BasicTable>
<!--历史-->
<HisTaskDealModal ref="taskDealRef" :path="path" :formData="formData"></HisTaskDealModal>
</div>
</template>
<script lang="ts" name="process-hisprocess-list" setup>
import { ref, unref } from 'vue';
import { BasicTable, TableAction } from '/@/components/Table';
import HisTaskDealModal from '../components/HisTaskDealModal.vue';
import { useBpmNodeInfo } from '../components/hooks/useBpmNodeInfo';
import { columns, searchFormSchema } from './hisprocess.data';
import { list, invalidProcess, callBackProcess } from './hisprocess.api';
import { useListPage } from '/@/hooks/system/useListPage';
// 列表页面公共参数、方法
const { prefixCls, tableContext } = useListPage({
designScope: 'process-hisprocess',
tableProps: {
api: list,
columns: columns,
formConfig: {
schemas: searchFormSchema,
},
actionColumn: {
width: 120,
fixed: 'right',
},
},
});
const path = ref('');
const taskDealRef = ref(null);
const { getHisProcessNodeInfo, formData } = useBpmNodeInfo(path, taskDealRef);
const [registerTable, rowSelection, { reload }] = tableContext;
/**
* 显示历史
* @param record
*/
function showHistory(record) {
getHisProcessNodeInfo(record);
}
/**
* 作废流程
* @param record
*/
async function handleInvalidProcess(record) {
await invalidProcess(
{
processInstanceId: record.processInstanceId,
},
reload
);
}
/**
* 取回流程
* @param record
*/
async function handleCallBackProcess(record) {
await callBackProcess(
{
processInstanceId: record.processInstanceId,
},
reload
);
}
/**
* 操作栏
*/
function getTableAction(record) {
return [
{
label: '历史',
onClick: showHistory.bind(null, record),
ifShow: () => {
return record.endTime && record.endTime != '';
},
},
];
}
/**
* 下拉操作栏
*/
function getDropDownAction(record) {
return [
{
label: '作废流程',
popConfirm: {
title: '确定要作废流程吗?',
confirm: handleInvalidProcess.bind(null, record),
},
ifShow: () => {
return !record.endTime;
},
},
{
label: '取回流程',
popConfirm: {
title: '确定要取回流程吗?',
confirm: handleCallBackProcess.bind(null, record),
},
ifShow: () => {
return !record.endTime;
},
},
{
label: '历史',
onClick: showHistory.bind(null, record),
ifShow: () => {
return !record.endTime;
},
},
];
}
</script>
@@ -0,0 +1,10 @@
import { defHttp } from '/@/utils/http/axios';
enum Api {
list = '/act/task/taskAllHistoryList',
}
/**
* 列表
* @param params
*/
export const list = (params) => defHttp.get({ url: Api.list, params });
@@ -0,0 +1,65 @@
import { FormSchema } from '/@/components/Table';
export const columns = [
{
title: '业务标题',
dataIndex: 'bpmBizTitle',
width: 180,
ellipsis: true,
},
{
title: '流程名称',
dataIndex: 'processDefinitionName',
width: 180,
},
{
title: '流程实例',
dataIndex: 'processInstanceId',
width: 180,
},
{
title: '任务名称',
dataIndex: 'taskName',
},
{
title: '发起人',
dataIndex: 'processApplyUserName',
},
{
title: '办理人',
dataIndex: 'taskAssigneeName',
},
{
title: '开始时间',
dataIndex: 'taskBeginTime',
},
{
title: '结束时间',
dataIndex: 'taskEndTime',
},
{
title: '耗时',
dataIndex: 'durationStr',
},
{
title: '流程编号',
dataIndex: 'processDefinitionId',
},
];
/**
* 列表查询form
*/
export const searchFormSchema: FormSchema[] = [
{
field: 'processDefinitionId',
label: '流程编号',
component: 'Input',
colProps: { span: 6 },
},
{
field: 'processDefinitionName',
label: '流程名称',
component: 'Input',
colProps: { span: 6 },
},
];
@@ -0,0 +1,60 @@
<template>
<div>
<BasicTable @register="registerTable" :rowSelection="rowSelection">
<!--操作栏-->
<template #action="{ record }">
<TableAction :actions="getTableAction(record)" />
</template>
</BasicTable>
<!--历史-->
<HisTaskDealModal ref="taskDealRef" :path="path" :formData="formData"></HisTaskDealModal>
</div>
</template>
<script lang="ts" name="process-histask-list" setup>
import { ref, unref } from 'vue';
import { BasicTable, TableAction } from '/@/components/Table';
import HisTaskDealModal from '../components/HisTaskDealModal.vue';
import { columns, searchFormSchema } from './histask.data';
import { list } from './histask.api';
import { useListPage } from '/@/hooks/system/useListPage';
import { useBpmNodeInfo } from '../components/hooks/useBpmNodeInfo';
// 列表页面公共参数、方法
const { prefixCls, tableContext } = useListPage({
designScope: 'process-histask',
tableProps: {
api: list,
columns: columns,
formConfig: {
schemas: searchFormSchema,
},
actionColumn: {
width: 120,
fixed: 'right',
},
},
});
const [registerTable, rowSelection, { reload }] = tableContext;
const path = ref('');
const taskDealRef = ref(null);
let { getHisProcessNodeInfo, formData } = useBpmNodeInfo(path, taskDealRef);
/**
* 显示历史
* @param record
*/
function showHistory(record) {
getHisProcessNodeInfo(record);
}
/**
* 操作栏
*/
function getTableAction(record) {
return [
{
label: '历史',
onClick: showHistory.bind(null, record),
},
];
}
</script>
@@ -0,0 +1,52 @@
<template>
<BasicModal v-bind="$attrs" @register="registerModal" :title="title" @ok="handleSubmit" :width="700">
<BasicForm @register="registerForm" />
</BasicModal>
</template>
<script lang="ts" setup>
import { ref, computed, unref } from 'vue';
import { BasicModal, useModalInner } from '/@/components/Modal';
import { BasicForm, useForm } from '/@/components/Form/index';
import { formSchema } from '../listener.data';
import { saveOrUpdate } from '../listener.api';
// 声明Emits
const emit = defineEmits(['success', 'register']);
const isUpdate = ref(true);
//表单配置
const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({
// labelWidth: 150,
schemas: formSchema,
showActionButtonGroup: false,
});
//表单赋值
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
//重置表单
await resetFields();
setModalProps({ confirmLoading: false });
isUpdate.value = !!data?.isUpdate;
if (unref(isUpdate)) {
//表单赋值
await setFieldsValue({
...data.record,
});
}
});
//设置标题
const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑'));
//表单提交事件
async function handleSubmit() {
try {
const values = await validate();
setModalProps({ confirmLoading: true });
//提交表单
await saveOrUpdate(values, isUpdate.value);
//关闭弹窗
closeModal();
//刷新列表
emit('success');
} finally {
setModalProps({ confirmLoading: false });
}
}
</script>
@@ -0,0 +1,41 @@
import { defHttp } from '/@/utils/http/axios';
enum Api {
list = '/act/process/extActListener/list',
save = '/act/process/extActListener/add',
edit = '/act/process/extActListener/edit',
delete = '/act/process/extActListener/delete',
changeStatus = '/act/process/extActListener/changeStatus',
}
/**
* 列表
* @param params
*/
export const list = (params) => defHttp.get({ url: Api.list, params });
/**
* 保存或者更新
* @param params
*/
export const saveOrUpdate = (params, isUpdate) => {
let url = isUpdate ? Api.edit : Api.save;
return isUpdate ? defHttp.put({ url: url, params }) : defHttp.post({ url: url, params });
};
/**
* 删除监听
* @param params
*/
export const deleteOne = (params, handleSuccess) => {
return defHttp.delete({ url: Api.delete, data: params }, { joinParamsToUrl: true }).then(() => {
handleSuccess();
});
};
/**
* 修改状态
* @param params
*/
export const changeStatus = (params, handleSuccess) => {
return defHttp.put({ url: Api.changeStatus, data: params }).then(() => {
handleSuccess();
});
};
@@ -0,0 +1,164 @@
import { FormSchema } from '/@/components/Table';
import { render } from '/@/utils/common/renderUtils';
export const columns = [
{
title: '名称',
dataIndex: 'listenerName',
width: 180,
ellipsis: true,
},
{
title: '监听类型',
dataIndex: 'listenerType',
width: 100,
customRender: ({ text }) => {
return render.renderDictNative(
text,
[
{ label: '执行监听', value: 1 },
{ label: '任务监听', value: 2 },
],
false
);
},
},
{
title: '事件',
dataIndex: 'listenerEvent',
width: 100,
},
{
title: '执行类型',
dataIndex: 'listenerValueType',
width: 150,
customRender: ({ text }) => {
return render.renderDictNative(
text,
[
{ label: '表达式', value: 'expression' },
{ label: 'JAVA类', value: 'javaClass' },
{ label: 'Spring表达式', value: 'delegateExpression' },
],
false
);
},
},
{
title: '执行内容',
dataIndex: 'listenerValue',
width: 360,
ellipsis: true,
},
{
title: '状态',
dataIndex: 'listenerStatus',
width: 100,
customRender: ({ text }) => {
return render.renderDictNative(
text,
[
{ label: '已禁用', value: '0' },
{ label: '已启用', value: '1' },
],
false
);
},
},
];
/**
* 列表查询form
*/
export const searchFormSchema: FormSchema[] = [
{
field: 'listenerName',
label: '名称',
component: 'Input',
colProps: { span: 6 },
},
];
/**
* 表单form
*/
export const formSchema: FormSchema[] = [
{
field: 'id',
label: '',
component: 'Input',
show: false,
},
{
label: '名称',
field: 'listenerName',
required: true,
component: 'Input',
},
{
label: '监听类型',
field: 'listenerType',
component: 'Select',
componentProps: ({ formModel }) => {
return {
options: [
{ label: '执行监听', value: 1 },
{ label: '任务监听', value: 2 },
],
onChange: () => {
formModel.listenerEvent = '';
},
};
},
},
{
label: '事件属性',
field: 'listenerEvent',
component: 'Select',
componentProps: ({ formModel }) => {
const isExecute = [
{ label: 'start', value: 'start' },
{ label: 'end', value: 'end' },
{ label: 'take', value: 'take' },
];
const isTask = [
{ label: 'create', value: 'create' },
{ label: 'assignment', value: 'assignment' },
{ label: 'complete', value: 'complete' },
];
let option = !formModel['listenerType'] ? [] : formModel['listenerType'] == 1 ? isExecute : isTask;
return {
options: option,
};
},
},
{
label: '值类型',
field: 'listenerValueType',
component: 'RadioGroup',
defaultValue: 'javaClass',
componentProps: ({ formActionType }) => {
return {
options: [
{ label: 'JAVA类', value: 'javaClass' },
{ label: '表达式', value: 'expression' },
{ label: '代理表达式', value: 'delegateExpression' },
],
onChange: (e) => {
const { updateSchema } = formActionType;
let value = e.target.value;
const label = value === 'javaClass' ? '类路径' : '表达式';
updateSchema([
{
field: 'listenerValue',
label: label,
},
]);
},
};
},
},
{
label: '类路径',
field: 'listenerValue',
component: 'Input',
},
];
@@ -0,0 +1,125 @@
<template>
<div>
<BasicTable @register="registerTable" :rowSelection="rowSelection">
<template #tableTitle>
<a-button type="primary" preIcon="ant-design:plus-outlined" @click="handleCreate"> 新增</a-button>
</template>
<!--操作栏-->
<template #action="{ record }">
<TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)" />
</template>
</BasicTable>
<!--监听弹窗-->
<ListenerModal @register="registerModal" @success="reload"></ListenerModal>
</div>
</template>
<script lang="ts" name="process-listener-list" setup>
import { ref } from 'vue';
import { BasicTable, TableAction } from '/@/components/Table';
import ListenerModal from './components/ListenerModal.vue';
import { useModal } from '/@/components/Modal';
import { columns, searchFormSchema } from './listener.data';
import { list, deleteOne, changeStatus } from './listener.api';
import { useListPage } from '/@/hooks/system/useListPage';
//弹窗
const [registerModal, { openModal }] = useModal();
// 列表页面公共参数、方法
const { prefixCls, tableContext } = useListPage({
designScope: 'process-listener',
tableProps: {
title: '流程监听',
api: list,
columns: columns,
formConfig: {
labelWidth: 50,
schemas: searchFormSchema,
},
actionColumn: {
width: 120,
fixed: 'right',
},
},
});
const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext;
/**
* 新增
*/
function handleCreate() {
openModal(true, {
isUpdate: false,
});
}
/**
* 编辑
*/
function handleEdit(record: Recordable) {
console.log('点击了编辑', record);
openModal(true, {
record,
isUpdate: true,
});
}
/**
* 删除
* @param id
*/
async function handleDelete(id) {
console.log('点击了删除', id);
await deleteOne({ id }, reload);
}
/**
* 修改状态
* @param id
*/
async function handleOpen(id) {
console.log('点击了启用', id);
await changeStatus({ id }, reload);
}
/**
* 操作栏
*/
function getTableAction(record) {
return [
{
label: '编辑',
onClick: handleEdit.bind(null, record),
},
{
label: '启用',
popConfirm: {
title: '是否启用?',
confirm: handleOpen.bind(null, record.id),
},
ifShow: () => {
return record.listenerStatus == 0;
},
},
{
label: '禁用',
popConfirm: {
title: '是否禁用?',
confirm: handleOpen.bind(null, record.id),
},
ifShow: () => {
return record.listenerStatus == 1;
},
},
];
}
/**
* 下拉操作栏
*/
function getDropDownAction(record) {
return [
{
label: '删除',
popConfirm: {
title: '是否确认删除',
confirm: handleDelete.bind(null, record.id),
},
},
];
}
</script>
@@ -0,0 +1,61 @@
import { defHttp } from '/@/utils/http/axios';
enum Api {
list = '/act/processInstance/list',
suspend = '/act/processInstance/suspend',
restart = '/act/processInstance/restart',
close = '/act/processInstance/close',
taskEntrust = '/act/task/taskEntrust',
taskComplaint = '/act/task/taskComplaint',
}
/**
* 列表
* @param params
*/
export const list = (params) => defHttp.get({ url: Api.list, params });
/**
* 激活
* @param params
*/
export const restart = (params, handleSuccess) => {
return defHttp.get({ url: Api.restart, params }).then(() => {
handleSuccess();
});
};
/**
* 挂起
* @param params
*/
export const suspend = (params, handleSuccess) => {
return defHttp.get({ url: Api.suspend, params }).then(() => {
handleSuccess();
});
};
/**
* 关闭
* @param params
*/
export const closeProcess = (params, handleSuccess) => {
return defHttp.get({ url: Api.close, params }).then(() => {
handleSuccess();
});
};
/**
* 委派
* @param params
*/
export const taskEntrust = (params, handleSuccess) => {
return defHttp.put({ url: Api.taskEntrust, params }).then(() => {
handleSuccess();
});
};
/**
* 转办
* @param params
*/
export const taskComplaint = (params, handleSuccess) => {
return defHttp.put({ url: Api.taskComplaint, params }).then(() => {
handleSuccess();
});
};
@@ -0,0 +1,77 @@
import { FormSchema } from '/@/components/Table';
export const columns = [
{
title: '流程名称',
dataIndex: 'prcocessDefinitionName',
width: 180,
ellipsis: true,
},
{
title: '业务标题',
dataIndex: 'bpmBizTitle',
},
{
title: '当前任务',
dataIndex: 'name',
},
{
title: '流程实例',
dataIndex: 'processInstanceId',
width: 180,
},
{
title: '办理人',
dataIndex: 'assigneeName',
width: 100,
},
{
title: '流程ID',
dataIndex: 'processDefinitionId',
width: 150,
},
{
title: '开始时间',
dataIndex: 'startTime',
},
{
title: '发起人',
dataIndex: 'startUserName',
width: 100,
},
{
title: '耗时',
dataIndex: 'spendTimes',
},
{
title: '状态',
dataIndex: 'isSuspended',
width: 80,
customRender: ({ text }) => {
return text === 'true' ? '已暂停' : '已启动';
},
},
];
/**
* 列表查询form
*/
export const searchFormSchema: FormSchema[] = [
{
field: 'processInstanceId',
label: '流程实例ID',
component: 'Input',
colProps: { span: 6 },
},
{
field: 'startUserId',
label: '流程发起人',
component: 'JSelectUserByDept',
componentProps: {
labelKey: 'realname',
rowKey: 'username',
showButton: false,
maxSelectCount: 1,
},
colProps: { span: 6 },
},
];
@@ -0,0 +1,202 @@
<template>
<div>
<BasicTable @register="registerTable" :rowSelection="rowSelection">
<!--操作栏-->
<template #action="{ record }">
<TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)" />
</template>
</BasicTable>
<!--委派弹窗-->
<DelegateModal @register="registerModal" @success="handleEntruster" title="请选择委派人"></DelegateModal>
<!--转办弹窗-->
<DelegateModal @register="registerModalComplaint" @success="handleComplaint" title="请选择转办人"></DelegateModal>
<!--跳转弹窗-->
<SelectTaskNodeModal @register="registerSkipModal" @success="reload"></SelectTaskNodeModal>
<!--历史-->
<HisTaskDealModal ref="taskDealRef" :path="path" :formData="formData"></HisTaskDealModal>
</div>
</template>
<script lang="ts" name="process-instance-list" setup>
import { ref, unref } from 'vue';
import { BasicTable, TableAction } from '/@/components/Table';
import DelegateModal from '../components/DelegateModal.vue';
import SelectTaskNodeModal from '../components/SelectTaskNodeModal.vue';
import HisTaskDealModal from '../components/HisTaskDealModal.vue';
import { useModal } from '/@/components/Modal';
import { columns, searchFormSchema } from './instance.data';
import { list, suspend, restart, closeProcess, taskEntrust, taskComplaint } from './instance.api';
import { useListPage } from '/@/hooks/system/useListPage';
import { useBpmNodeInfo } from '../components/hooks/useBpmNodeInfo';
//委派弹窗
const [registerModal, { openModal }] = useModal();
//委派弹窗
const [registerModalComplaint, { openModal: openModalComplaint }] = useModal();
//跳转弹窗
const [registerSkipModal, { openModal: openSkipModal }] = useModal();
// 列表页面公共参数、方法
const { prefixCls, tableContext } = useListPage({
designScope: 'process-expression',
tableProps: {
api: list,
isTreeTable: true,
rowKey: 'processInstanceId',
columns: columns,
formConfig: {
schemas: searchFormSchema,
},
actionColumn: {
width: 120,
fixed: 'right',
},
},
});
const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext;
const taskId = ref('');
const path = ref('');
const taskDealRef = ref(null);
let { getHisProcessNodeInfo, formData } = useBpmNodeInfo(path, taskDealRef);
/**
* 激活
* @param id
*/
async function handleRestart(id) {
await restart({ processInstanceId: id }, reload);
}
/**
* 挂起
* @param id
*/
async function handleSuspend(id) {
await suspend({ processInstanceId: id }, reload);
}
/**
* 关闭
* @param id
*/
async function handleClose(id) {
await closeProcess({ processInstanceId: id }, reload);
}
/**
* 选择委派人员弹窗
* @param record
*/
function handleSelectEntruster(record) {
taskId.value = record.taskId;
openModal(true);
}
/**
* 选择转办人员弹窗
* @param record
*/
function handleSelectComplaint(record) {
taskId.value = record.taskId;
openModalComplaint(true);
}
/**
* 跳转
* @param taskId
*/
function handleSkipNode(taskId) {
openSkipModal(true, { taskId });
}
/**
* 显示历史
* @param record
*/
function showHistory(record) {
getHisProcessNodeInfo(record);
}
/**
* 委派
* @data
*/
async function handleEntruster(data) {
console.log('handleEntruster委派返回值data', data);
let params = { taskId: unref(taskId), taskAssignee: data.username };
await taskEntrust(params, reload);
}
/**
* 转办
* @data
*/
async function handleComplaint(data) {
console.log('handleComplaint转办返回值data', data);
let params = { taskId: unref(taskId), taskAssignee: data.username };
await taskComplaint(params, reload);
}
/**
* 操作栏
*/
function getTableAction(record) {
return [
{
label: '激活',
popConfirm: {
title: '是否激活?',
confirm: handleRestart.bind(null, record.id),
},
ifShow: () => {
return record.isSuspended != '' && record.isSuspended === 'true';
},
},
{
label: '挂起',
popConfirm: {
title: '是否挂起?',
confirm: handleSuspend.bind(null, record.id),
},
ifShow: () => {
return record.isSuspended != '' && record.isSuspended === 'false';
},
},
];
}
/**
* 下拉操作栏
*/
function getDropDownAction(record) {
return [
{
label: '关闭',
popConfirm: {
title: '是否关闭吗?',
confirm: handleClose.bind(null, record.id),
},
ifShow: () => {
return record.isSuspended != '' && record.isSuspended != 'finished';
},
},
{
label: '转办',
onClick: handleSelectComplaint.bind(null, record),
ifShow: () => {
return record.isSuspended != '' && record.isSuspended === 'false' && record.isSuspended != 'finished';
},
},
{
label: '委派',
onClick: handleSelectEntruster.bind(null, record),
ifShow: () => {
return record.isSuspended != '' && record.isSuspended === 'false' && record.isSuspended != 'finished';
},
},
{
label: '跳转',
onClick: handleSkipNode.bind(null, record.taskId),
ifShow: () => {
return record.isSuspended != '';
},
},
{
label: '历史',
onClick: showHistory.bind(null, record),
ifShow: () => {
return record.isSuspended != '';
},
},
];
}
</script>