Browse Source

chore: work task components compose

master
wangxiang 2 years ago
parent
commit
b5233b58db
No known key found for this signature in database
GPG Key ID: 1BA7946AB6B232E4
  1. 66
      src/views/workflow/task/TaskForm.vue
  2. 73
      src/views/workflow/task/WorkflowChartModel.vue
  3. 15
      src/views/workflow/task/WorkflowPreviewForm.vue
  4. 130
      src/views/workflow/task/WorkflowTimeLine.vue
  5. 75
      src/views/workflow/task/workflowStep/index.vue
  6. 45
      src/views/workflow/task/workflowStep/workflowStep.data.ts

66
src/views/workflow/task/TaskForm.vue

@ -2,9 +2,10 @@ @@ -2,9 +2,10 @@
<div :class="prefixCls">
<ALayoutContent class="m-10">
<h4 class="text-center text-lg pb-2">{{ state.formTitle }}</h4>
<ATable v-model:activeKey="state.taskSelectedTab"
<ATables v-model:activeKey="state.taskSelectedTab"
class="bg-white"
:tab-bar-style="{ 'padding-left': '13px' }"
@tabClick="handleTabsClick"
>
<ATabPane key="formInfo">
<template #tab>
@ -12,9 +13,9 @@ @@ -12,9 +13,9 @@
<Icon icon="fa6-solid:file-lines"/>表单信息
</span>
</template>
<!-- 动态表单:内置使用枇杷表单设计器 -->
<!-- 动态表单:内置使用枇杷表单设计器(待更新为海豚表单设计器) -->
<workflow-preview-form v-if="state.formType !== '2'"
ref="form"
ref="formPreview"
:taskFormData="state.taskFormData"
/>
<!-- 外置表单:内置使用用户自定义的vue页面,手动填写页面路径即可 -->
@ -25,14 +26,31 @@ @@ -25,14 +26,31 @@
:businessId="state.businessId"
/>
</ATabPane>
<ATabPane key="processInfo">
<template #tab>
<span>
<Icon icon="fa6-solid:money-bill-wheat"/>流程信息
</span>
</template>
<WorkflowTimeLine/>
</ATabPane>
<ATabPane key="processChart">
<template #tab>
<span>
<Icon icon="fa-solid:image"/>流程图
</span>
</template>
<WorkflowChartModel ref="workflowChart"/>
</ATabPane>
<ATabPane key="flowRecord">
<template #tab>
<span>
<Icon icon="fa6-solid:bars-progress"/>流转记录
</span>
</template>
<WorkflowStep/>
</ATabPane>
</ATable>
</ATables>
<a-card v-if="!state.processInsId || state.taskId || state.status === 'reStart'" style="margin-top:10px;margin-bottom:66px;">
<AForm
ref="auditForm"
@ -114,6 +132,9 @@ @@ -114,6 +132,9 @@
import { useModal } from '/@/components/Modal';
import type { KiccUser } from '/@/api/common/base/entity';
import WorkflowPreviewForm from './WorkflowPreviewForm.vue';
import WorkflowChartModel from './WorkflowChartModel.vue';
import WorkflowTimeLine from './WorkflowTimeLine.vue';
import WorkflowStep from './workflowStep/index.vue';
import { getProcessStartEventFormData, getTaskFormData } from '/@/api/platform/workflow/controller/form';
import { findByDefIdAndTaskId } from '/@/api/platform/workflow/extension/controller/activityExtensionData';
import { useDesign } from '/@/hooks/web/useDesign';
@ -175,7 +196,7 @@ @@ -175,7 +196,7 @@
/** 通用变量统一声明区域 */
const ALayoutContent = LayoutContent;
const ATable = Tabs;
const ATables = Tabs;
const ATabPane = Tabs.TabPane;
const AForm = Form;
const AFormItem = Form.Item;
@ -220,21 +241,13 @@ @@ -220,21 +241,13 @@
const { params, query } = unref(currentRoute);
const { notification, createMessage, createConfirm } = useMessage();
const { close } = useTabs();
const form = ref();
const formPreview = ref();
const workflowChart = ref();
const [registerUser , { openModal: openUser }] = useModal();
const [registerRollBackTask , { openModal: openRollBackTask }] = useModal();
onActivated(() => {
handleInit();
nextTick(async () => {
//
if (state.processInsId) {
const data = await getFlowChart(state.processInsId);
//this.$refs.flowableChart.setHighlightImportDiagram(response)
} else {
const data = getProcessDefFlowChart(state.processDefId);
//this.$refs.flowableChart.setHighlightImportDiagram({ bpmnXml: data })
}
//
if (state.formType === '2') {
if (state.formKey === '/404') {
@ -246,9 +259,9 @@ @@ -246,9 +259,9 @@
//
} else {
if (state.formKey === '/404') {
form.value.init('');
formPreview.value.init('');
} else {
form.value.init(state.formKey);
formPreview.value.init(state.formKey);
}
//
if (state.status === 'start' || state.status === 'reStart') {
@ -258,7 +271,6 @@ @@ -258,7 +271,6 @@
state.taskFormData = await getTaskFormData(state.taskId);
}
}
//
if (state.status === 'start' || state.status === 'reStart') {
state.buttons = [{ code: '_workflow_activity_start', name: '启动', isHide: '0' }];
@ -323,7 +335,7 @@ @@ -323,7 +335,7 @@
function start(vars: Recordable) {
//
if (state.formType === '2') {
form.value.startProcessDefinition(async (businessTable: string, businessId: string) => {
formPreview.value.startProcessDefinition(async (businessTable: string, businessId: string) => {
const processInsId = await startProcessDefinition({
processDefKey: this.processDefKey,
businessTable: businessTable,
@ -336,7 +348,7 @@ @@ -336,7 +348,7 @@
});
//
} else {
form.value.startFormProcessDefinition({ processDefId: this.processDefId, ...vars }, (processInsId: string) => {
formPreview.value.startFormProcessDefinition({ processDefId: this.processDefId, ...vars }, (processInsId: string) => {
close();
push({ path: '/workflow/task/index' });
cc({ processInsId });
@ -421,7 +433,7 @@ @@ -421,7 +433,7 @@
function commit(vars?: Recordable) {
//
if (state.formType === '2') {
form.value.auditTask(async () => {
formPreview.value.auditTask(async () => {
await auditTask({
taskId: this.taskId,
taskDefKey: this.taskDefKey,
@ -437,7 +449,7 @@ @@ -437,7 +449,7 @@
});
//
} else {
form.value.auditFormTask({
formPreview.value.auditFormTask({
taskId: this.taskId,
processInsId: this.processInsId,
activityCommentInfo: this.auditForm,
@ -547,6 +559,16 @@ @@ -547,6 +559,16 @@
};
});
function handleTabsClick(activeKey: string, event: MouseEvent) {
// fixme: tabstab
if (activeKey === 'processChart' && !workflowChart.value) {
setTimeout(() => {
//
workflowChart.value.init(state.processInsId, state.processDefId);
}, 100);
}
}
</script>
<style lang="less" scoped>
@prefix-cls: ~'@{namespace}-task-form';

73
src/views/workflow/task/WorkflowChartModel.vue

@ -0,0 +1,73 @@ @@ -0,0 +1,73 @@
<template>
<div id="workflowChart" v-loading="state.loading"/>
</template>
<script lang="ts" setup>
import { reactive, onDeactivated } from 'vue';
import { loadMicroApp, MicroApp } from 'qiankun';
import { getSubDefineProps } from '/@/qiankun/state';
import { GlStateEnum, WORKFLOW_DESIGN_APP_COMPONENTS } from '/@/enums/microAppEnum';
import { useMicroAppStore } from '/@/store/modules/microApp';
import { apps } from '/@/qiankun/apps';
import { useMessage } from '/@/hooks/web/useMessage';
import { getFlowChart as getProcessDefFlowChart } from '/@/api/platform/workflow/controller/process';
import { getFlowChart as getProcessInsFlowChart } from '/@/api/platform/workflow/controller/task';
interface WindowState {
workflowDesignApp: MicroApp;
loading: boolean;
bpmnData: Recordable;
}
const state = reactive<WindowState>({
workflowDesignApp: undefined!,
loading: false,
bpmnData: {}
});
const workflowDesignProps = {
style: { 'min-height': '100vh' },
};
const microAppStore = useMicroAppStore();
const { createMessage } = useMessage();
async function init(processInsId: string, processDefId: string) {
if (processInsId || processDefId) {
state.loading = true;
// xml
try {
if (this.processInsId) {
state.bpmnData = await getProcessInsFlowChart(processInsId);
} else {
const bpmnXml = await getProcessDefFlowChart(processDefId);
state.bpmnData = { bpmnXml };
}
state.workflowDesignApp?.unmount();
state.workflowDesignApp = loadMicroApp(Object.assign({} , apps.find(item => item.name == 'workflow-design'), {
container: '#workflowChart',
props: {
...getSubDefineProps(),
mountApp: WORKFLOW_DESIGN_APP_COMPONENTS.CHART,
[GlStateEnum.WORKFLOW_DESIGN_APP_PROPS_KEY]: workflowDesignProps
}
}), { sandbox: { experimentalStyleIsolation: true }});
state.workflowDesignApp.mountPromise.then(() => {
const workflowChartApp: Recordable = microAppStore.getWorkflowDesignApp(WORKFLOW_DESIGN_APP_COMPONENTS.CHART),
workflowRef: Recordable = workflowChartApp.getRef().$refs['workflow-chart'];
workflowRef.setHighlightImportDiagram(state.bpmnData);
state.loading = false;
});
} catch(e: any) {
createMessage.error(e);
state.loading = false;
}
} else createMessage.error('无法打开流程图,没有关联流程图ID!');
}
onDeactivated(() => {
state.workflowDesignApp?.unmount();
});
defineExpose({
init
});
</script>

15
src/views/workflow/task/WorkflowPreviewForm.vue

@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
<div id="formPreview" v-loading="state.loading"/>
</template>
<script lang="ts" setup>
import { PropType, reactive, onDeactivated, onUpdated } from 'vue';
import { PropType, reactive, onDeactivated } from 'vue';
import { loadMicroApp, MicroApp } from 'qiankun';
import { getSubDefineProps } from '/@/qiankun/state';
import { GlStateEnum } from '/@/enums/microAppEnum';
@ -44,7 +44,6 @@ @@ -44,7 +44,6 @@
disabled: false,
readonly: false,
};
const emit = defineEmits(['success', 'register']);
const microAppStore = useMicroAppStore();
const { createMessage } = useMessage();
@ -52,6 +51,12 @@ @@ -52,6 +51,12 @@
if (formJsonId) {
state.loading = true;
state.formData = {};
// json
try {
const data = await getFormDefinitionJson(formJsonId);
if (!data.json) throw Error('当前数据没有json结构体');
formDesignProps.options = eval('(' + data.json + ')');
state.formDesignApp?.unmount();
state.formDesignApp = loadMicroApp(Object.assign({} , apps.find(item => item.name == 'form-design'), {
container: '#formPreview',
props: {
@ -81,13 +86,9 @@ @@ -81,13 +86,9 @@
formRef.setDisableIds(disableIds);
state.loading = false;
});
// json
try {
const data = await getFormDefinitionJson(formJsonId);
if (!data.json) throw Error('当前数据没有json结构体');
formDesignProps.options = eval('(' + data.json + ')');
} catch(e: any) {
createMessage.error(e);
state.loading = false;
}
} else createMessage.info('没有关联流程表单!');
}

130
src/views/workflow/task/WorkflowTimeLine.vue

@ -0,0 +1,130 @@ @@ -0,0 +1,130 @@
<template>
<a-card :class="prefixCls" title="流程信息" :bordered="false">
<a-timeline>
<a-timeline-item color="#3f9eff">
<div class="workflow">
<div class="timestamp">{{formatToDateTime()}}</div>
<a-card>
<h4>{{'管理员审批'}}</h4>
<a-row :gutter="25">
<a-col class="tip" style="margin-left:10px" :span="11">
<div class="item">
<span class="label">审批人 : </span>
<span class="value">{{'虚拟内容'}}</span>
</div>
<div class="item">
<span class="label">办理状态 : </span>
<span class="value">
<!-- <a-tag :type="historyFlowChange.activityCommentInfo.mesLevel"
effect="dark"
size="small"
>{{'虚拟内容}}</a-tag>-->
</span>
</div>
<div class="item">
<span class="label">审批意见 : </span>
<!-- <a-tooltip effect="dark"
:content="historyFlowChange.activityCommentInfo.message"
placement="top-start"
>
<span class="value">{{'虚拟内容'}}</span>
</a-tooltip>-->
</div>
<div class="item">
<span class="label">开始时间 : </span>
<span class="value">{{'虚拟内容'}}</span>
</div>
<div class="item">
<span class="label">结束时间 : </span>
<span class="value">{{'虚拟内容'}}</span>
</div>
<div class="item">
<span class="label">用时 : </span>
<span class="value">{{'虚拟内容'}}</span>
</div>
</a-col>
</a-row>
</a-card>
</div>
</a-timeline-item>
</a-timeline>
</a-card>
</template>
<script lang="ts" setup>
/**
* 提供模板规范代码参考,请尽量保证编写代码风格跟模板规范代码一致
* 采用vben-动态表格表单封装组件编写,采用 setup 写法
* Copyright © 2023-2023 <a href="https://godolphinx.org">海豚生态开源社区</a> All rights reserved.
* author wangxiang4
*/
import { PropType } from 'vue';
import { Workflow } from '/@/api/platform/workflow/entity/workflow';
import { Timeline } from 'ant-design-vue';
import { formatToDateTime } from '/@/utils/dateUtil';
import { useDesign } from '/@/hooks/web/useDesign';
const ATimeline = Timeline;
const ATimelineItem = Timeline.Item;
const { prefixCls } = useDesign('workflow-time-line');
const props = defineProps({
historyFlowChangeList: {
type: Array as PropType<Workflow[]>,
default: () => []
}
});
</script>
<style lang="less" scoped>
@prefix-cls: ~'@{namespace}-workflow-time-line';
.@{prefix-cls} {
.workflow{
.timestamp {
color: #909399;
padding-bottom: 12px;
}
.item {
height: 32px;
line-height: 32px;
margin-bottom: 8px;
.label {
display: inline-block;
height: 100%;
width: 70px;
font-size: 14px;
color: #5e6d82;
text-align: end;
vertical-align: top;
&::after {
display: inline-block;
width: 100%;
content: '';
height: 0;
}
}
.value {
padding-left: 10px;
font-size: 14px;
max-width: calc(100% - 90px);
color: #5e6d82;
display: inline-block;
overflow:hidden;
white-space:nowrap;
text-overflow: ellipsis
}
}
.tip {
padding: 8px 16px;
background-color: #ecf8ff;
border-radius: 4px;
border-left: 5px solid #50bfff;
margin: 20px 0;
}
}
}
</style>

75
src/views/workflow/task/workflowStep/index.vue

@ -0,0 +1,75 @@ @@ -0,0 +1,75 @@
<template>
<a-card :class="prefixCls" title="流转记录" :bordered="false">
<a-steps :current="current" size="small">
<a-step>
<template #title>开始</template>
<template #description>
<span>admin,2023-10-07 14:40:17</span>
</template>
</a-step>
<a-step title="小猫审批" description="小猫,2023-10-07 14:40:17"/>
<a-step title="小猫审批" description="小猫,2023-10-07 14:40:17"/>
<a-step title="小猫审批" description="小猫,2023-10-07 14:40:17"/>
<a-step title="小猫审批" description="小猫,2023-10-07 14:40:17"/>
<a-step title="小猫审批" description="小猫,2023-10-07 14:40:17"/>
</a-steps>
<BasicTable @register="registerTable"/>
</a-card>
</template>
<script lang="ts" setup name="WorkflowStep">
/**
* 提供模板规范代码参考,请尽量保证编写代码风格跟模板规范代码一致
* 采用vben-动态表格表单封装组件编写,采用 setup 写法
* Copyright © 2023-2023 <a href="https://godolphinx.org">海豚生态开源社区</a> All rights reserved.
* author wangxiang4
*/
import { PropType, ref } from 'vue';
import { Workflow } from '/@/api/platform/workflow/entity/workflow';
import { Steps } from 'ant-design-vue';
import { formatToDateTime } from '/@/utils/dateUtil';
import { useDesign } from '/@/hooks/web/useDesign';
import { BasicTable, useTable } from '/@/components/Table';
import { columns } from './workflowStep.data';
const ASteps = Steps;
const AStep = Steps.Step;
const { prefixCls } = useDesign('workflow-step');
const current = ref<number>(0);
const props = defineProps({
historyFlowChangeList: {
type: Array as PropType<Workflow[]>,
default: () => []
}
});
const [registerTable, { reload }] = useTable({
title: '流程进度列表',
//api: listProcessDef,
rowKey: 'id',
columns,
useSearchForm: false,
showTableSetting: true,
showIndexColumn: false,
});
</script>
<style lang="less" scoped>
@prefix-cls: ~'@{namespace}-workflow-step';
.@{prefix-cls} {
:deep(.ant-steps) {
&-item-content {
margin-top: 0;
}
&-item-title {
min-width: 20px;
}
&-item-description {
min-width: 200px;
}
}
}
</style>

45
src/views/workflow/task/workflowStep/workflowStep.data.ts

@ -0,0 +1,45 @@ @@ -0,0 +1,45 @@
import { BasicColumn } from '/@/components/Table';
import { h } from 'vue';
import { Tag } from 'ant-design-vue';
export const columns: BasicColumn[] = [
{
title: '执行环节',
dataIndex: ['historicActivityInstance', 'activityName'],
width: 200,
},
{
title: '执行人',
dataIndex: 'assigneeName',
width: 200,
},
{
title: '开始时间',
dataIndex: ['historicActivityInstance', 'startTime'],
width: 150
},
{
title: '结束时间',
dataIndex: ['historicActivityInstance', 'endTime'],
width: 150,
},
{
title: '办理状态',
dataIndex: ['activityCommentInfo', 'mesName'],
width: 200,
},
{
title: '审批意见',
dataIndex: ['activityCommentInfo', 'message'],
width: 200,
},
{
title: '任务历时',
dataIndex: 'durationTime',
width: 200,
customRender: ({ record }) => {
const durationTime = record.durationTime;
return h(Tag, { color: 'processing' }, () => durationTime || '0秒');
}
}
];
Loading…
Cancel
Save