提交 401f07d4 authored 作者: whydesc's avatar whydesc

--待阅处理

上级 517441ba
<template>
<div class="app-container">
<a-card class="box-card" :body-style="{ padding: '0' }">
<a-tabs
v-model:activeKey="activeName"
@tab-click="handleTabClick"
:tab-bar-style="{ margin: '0 24px', paddingTop: '8px' }"
class="process-tabs"
>
<!-- 当前表单标签页 -->
<a-tab-pane key="1" tab="当前表单" :force-render="true">
<div class="form-container">
<!-- 顶部操作栏 -->
<div class="action-header">
<!--
<div class="action-left">
<a-space>
<a-button type="primary" @click="handleReject" :loading="rejecting">
<template #icon><CloseCircleOutlined /></template>
驳回
</a-button>
<a-button type="primary" @click="handleAssignTask" :loading="assigning">
<template #icon><CloseCircleOutlined /></template>
转办
</a-button>
<a-button type="primary" @click="handleAssignReadTask" :loading="assiReadgning">
<template #icon><CloseCircleOutlined /></template>
转阅
</a-button>
</a-space>
</div>
<div class="action-right">
<div class="next-node-info">
<span class="next-node-label">下一节点:</span>
<a-select
v-model:value="nextNodeNameSele"
placeholder="请选择下一个节点"
style="width: 100%"
@change="handleChange"
v-if="shownextNodeNameSele"
>
<a-select-option v-for="item in tableOptions" :key="item.id" :value="item.value">
{{ item.name }}
</a-select-option>
</a-select>
<a-tag color="blue" class="next-node-tag" v-if="shownextNodeNametext">
{{ nextNodeName || '等待确定下一节点' }}
</a-tag>
</div>
</div>
-->
</div>
<div class="content-wrapper">
<!-- 左侧主表单 -->
<div class="main-form-section">
<!-- <a-card title="审批表单" :bordered="false" class="form-card">
<template #extra>
<a-button type="link" @click="refreshForm"> <ReloadOutlined /> 刷新 </a-button>
</template> -->
<div class="form-card">
<div v-show="formTp == 1" class="form-wrapper">
<FlowInnerForm ref="refCruInnerForm" :key="formKey" style="width: 100%; height: 100%" />
</div>
<div v-show="formTp == 2" class="form-wrapper">
<iFrame :key="formKey" :src="formUrl" class="responsive-iframe" style="width: 100%; height: 100%" />
</div>
</div>
<!-- </a-card> -->
</div>
<!-- 右侧审批栏
<div class="sidebar-section" v-if="showApprovalUi">
<a-card :title="approvalTitle" :bordered="false" class="approval-card">
<BasicForm @register="registerForm" style="width: 100%" />
<div class="form-footer">
<a-space :size="12">
<a-button @click="handleSendTask" type="primary">提交</a-button>
</a-space>
</div>
</a-card>
</div>
-->
</div>
</div>
</a-tab-pane>
<!-- 流程流转记录标签页 -->
<a-tab-pane key="2" tab="流转记录">
<div class="record-container">
<a-card :bordered="false" class="record-card">
<template #title>
<div class="record-title">
<HistoryOutlined />
<span style="margin-left: 8px">流程流转记录</span>
</div>
</template>
<div v-if="loadingFlowRecord" class="loading-state">
<a-spin tip="加载流转记录中..." />
</div>
<div v-else-if="flowRecordList.length === 0" class="empty-state">
<a-empty description="暂无流转记录" />
</div>
<a-timeline v-else class="flow-timeline">
<a-timeline-item v-for="(item, index) in flowRecordList" :key="index" :color="getTimelineColor(item.finishTime)">
<div class="timeline-item">
<div class="timeline-header">
<div class="task-name" style="margin: 5px 0px">
<a-tag :color="getTaskStatusColor(item.finishTime)" class="status-tag">
{{ item.finishTime ? '已完成' : '进行中' }}
</a-tag>
<span class="task-title">{{ item.taskName }}</span>
</div>
<div class="task-time">
<ClockCircleOutlined />
<span>{{ formatDuration(item.duration) }}</span>
</div>
</div>
<div class="timeline-content">
<a-descriptions size="small" :column="1" bordered>
<a-descriptions-item label="办理人" v-if="item.assigneeName">
<UserOutlined class="desc-icon" />
{{ item.assigneeName }}
<a-tag v-if="item.deptName" color="default" size="small">
{{ item.deptName }}
</a-tag>
</a-descriptions-item>
<a-descriptions-item label="候选办理" v-if="item.candidate">
<TeamOutlined class="desc-icon" />
{{ item.candidate }}
</a-descriptions-item>
<a-descriptions-item label="接收时间">
<CalendarOutlined class="desc-icon" />
{{ formatTime(item.createTime) }}
</a-descriptions-item>
<a-descriptions-item label="处理时间" v-if="item.finishTime">
<CheckCircleOutlined class="desc-icon" />
{{ formatTime(item.finishTime) }}
</a-descriptions-item>
<a-descriptions-item label="处理意见" v-if="item.comment?.comment">
<FormOutlined class="desc-icon" />
<div class="comment-box">
{{ item.comment?.comment }}
</div>
</a-descriptions-item>
</a-descriptions>
</div>
</div>
</a-timeline-item>
</a-timeline>
</a-card>
</div>
</a-tab-pane>
<!-- 流程图标签页 -->
<a-tab-pane key="3" tab="流程图">
<div class="flowchart-container">
<a-card :bordered="false" class="flowchart-card" :body-style="{ padding: '0', height: '100%', overflow: true }">
<template #title>
<div class="flowchart-title">
<DeploymentUnitOutlined />
<span style="margin-left: 8px">流程图</span>
</div>
</template>
<div class="bpmn-wrapper">
<div v-if="loadingFlowChart" class="loading-state">
<a-spin tip="加载流程图中..." size="large" />
</div>
<div class="bpmn-content">
<bpmn-viewer :flowData="flowData" :procInsId="taskForm.procInsId" @loaded="onFlowChartLoaded" />
</div>
</div>
</a-card>
</div>
</a-tab-pane>
</a-tabs>
</a-card>
<!-- 弹窗组件 -->
<Approve @register="registerApprove" ref="refApprove" />
<Reject @register="registerReject" ref="refReject" />
<Assign @register="registerAssign" ref="refAssign" />
<AssignRead @register="registerAssignRead" ref="refAssignRead" />
</div>
</template>
<script lang="ts" setup>
import { ref, reactive, nextTick, computed, watch } from 'vue';
import { message } from 'ant-design-vue';
import {
UserOutlined,
CalendarOutlined,
ClockCircleOutlined,
FormOutlined,
SendOutlined,
CloseCircleOutlined,
ReloadOutlined,
HistoryOutlined,
TeamOutlined,
CheckCircleOutlined,
DeploymentUnitOutlined,
} from '@ant-design/icons-vue';
// API
import { flowRecord } from '/@/components/Process/api/finished';
import { flowXmlAndNode } from '/@/components/Process/api/definition';
import { complete, flowTaskForm, getNextFlowNode, getMyTaskFlow, assign, assignRead } from '/@/components/Process/api/todo';
import { flowTaskInfo } from '/@/components/Process/api/process';
// 组件
import BpmnViewer from '/@/components/Process/viewer/index.vue';
import FlowInnerForm from '/@/views/flowable/task/components/FlowInnerForm.vue';
import Approve from './Approve.vue';
import Reject from './Reject.vue';
import Assign from './Assign.vue';
import AssignRead from './AssignRead.vue';
// 工具
import { useForm, BasicForm } from '/@/components/Form';
import { useModal } from '/@/components/Modal';
import dayjs from 'dayjs';
// 响应式数据
const activeName = ref('1');
const sending = ref(false);
const rejecting = ref(false);
const formLoading = ref(false);
const formError = ref(false);
const loadingFlowRecord = ref(false);
const loadingFlowChart = ref(false);
const formKey = ref(0);
const showApprovalUi = ref(true);
const flowData = ref<any>({});
const flowRecordList = ref<any[]>([]);
const nextNodeName = ref('');
const nextNode = ref<any>(null);
const nextNodenum = ref(0);
const tableOptions = ref([]);
const nextNodeNameSele = ref('');
const nextNodeNameSelevue = ref(0);
const shownextNodeNameSele = ref(true);
const shownextNodeNametext = ref(false);
const res0 = ref();
const res1 = ref();
const taskForm = reactive({
returnTaskShow: false,
delegateTaskShow: false,
defaultTaskShow: true,
comment: '',
procInsId: '',
instanceId: '',
deployId: '',
taskId: '',
procDefId: '',
targetKey: '',
values: {},
});
const workFlowData = ref<any>({});
const refCruInnerForm = ref<any>(null);
const isApproval = ref(false);
const formUrl = ref('');
const formTp = ref<any>();
const approvalTitle = ref('填写审批信息');
// 弹窗
const refApprove = ref(null);
const refReject = ref(null);
const refAssign = ref(null);
const refAssignRead = ref(null);
const [registerApprove, { openModal: openApproveModal }] = useModal();
const [registerReject, { openModal: openRejectModal }] = useModal();
const [registerAssign, { openModal: openAssignModal }] = useModal();
const [registerAssignRead, { openModal: openAssignReadModal }] = useModal();
// 转办表单配置
const assignFormSchemas = [
{
label: computed(() => (isApproval.value ? '审批人' : '接收人')),
field: 'checkSendUser',
component: 'JSelectUser',
required: true,
componentProps: {
allowClear: true,
rowKey: 'id',
labelKey: 'realname',
showButton: false,
modalTitle: computed(() => (isApproval.value ? '选择审批人' : '选择接收人')),
placeholder: computed(() => (isApproval.value ? '请选择审批人' : '请选择接收人')),
mode: 'multiple',
},
},
];
// 转办表单注册
const [registerAssignForm, { validate: validateAssign }] = useForm({
schemas: assignFormSchemas,
showActionButtonGroup: false,
});
// 计算属性
// const isFixed = computed(() => {
// return nextNode.value?.dataType === "fixed"
// })
const isFixed = ref(true);
const assigning = ref(false);
const assiReadgning = ref(false);
const userType = computed(() => {
return nextNode.value?.type || '';
});
// 表单配置
const formSchemas = [
{
label: '审批意见',
field: 'comment',
component: 'InputTextArea',
required: false,
componentProps: {
allowClear: true,
showCount: true,
autoSize: {
minRows: 6,
maxRows: 8,
},
placeholder: '请输入审批意见,如:同意、需补充材料等',
maxlength: 500,
},
rules: [
{ required: true, message: '请填写审批意见' },
{ min: 2, message: '至少输入2个字符' },
],
},
{
label: '接收人',
field: 'checkSendUser',
component: 'JSelectUser',
required: true,
componentProps: {
allowClear: true,
rowKey: 'id',
labelKey: 'realname',
showButton: false,
modalTitle: '选择接收人',
placeholder: '请选择接收人',
mode: 'multiple',
},
},
{
label: '抄送人',
field: 'copyUser',
component: 'JSelectUser',
required: false,
componentProps: {
allowClear: true,
rowKey: 'id',
labelKey: 'realname',
showButton: false,
modalTitle: '选择抄送人',
placeholder: '请选择抄送人',
mode: 'multiple',
},
},
{
label: '接收角色',
field: 'checkSendRole',
component: 'JSelectRole',
required: false,
ifShow: computed(() => userType.value !== 'user'),
componentProps: {
labelKey: 'roleName',
rowKey: 'id',
allowClear: true,
maxSelectCount: 3,
isRadioSelection: false,
placeholder: '请选择接收角色',
mode: 'multiple',
},
},
];
const [registerForm, { validate, setFieldsValue, removeSchemaByFiled, resetFields, updateSchema }] = useForm({
schemas: formSchemas as any,
showActionButtonGroup: false,
baseColProps: { span: 24 },
labelWidth: 100,
layout: 'vertical',
autoSubmitOnEnter: false,
//不显示重置按钮
showResetButton: false,
//自定义提交按钮文本和图标
submitButtonOptions: { text: '提交', preIcon: '' },
});
const emit = defineEmits(['callback', 'success', 'error']);
// 方法
const handleTabClick = async (key: string) => {
if (key === '1' && !formLoading.value) {
await initializeCruInnerForm();
}
if (key === '2' && flowRecordList.value.length === 0) {
await loadFlowRecord();
}
if (key === '3') {
await loadFlowChart();
}
};
const initializeCruInnerForm = async () => {
if (formLoading.value) return;
try {
formLoading.value = true;
formError.value = false;
await nextTick();
let { taskId } = taskForm;
if (!taskId) {
// try to resolve taskId by business id from workFlowData
const dataId = workFlowData.value?.dataId || workFlowData.value?.id || workFlowData.value?.businessId;
if (dataId) {
try {
const info = await flowTaskInfo({ dataId });
if (info?.taskId) {
taskForm.taskId = info.taskId;
taskId = info.taskId;
}
} catch (e) {
// ignore and fall through to error below
console.warn('flowTaskInfo 获取 taskId 失败', e);
}
}
}
if (!taskId) {
throw new Error('任务ID未设置');
}
const resData = await flowTaskForm({ taskId });
const { flowForm = {} } = resData;
// normalize form type to number for consistent comparisons
const tp = Number(flowForm.formTp);
formTp.value = tp;
if (tp === 1) {
// ensure the inner form component is recreated before initializing
formKey.value++;
await nextTick();
if (!refCruInnerForm.value) {
// wait a tick more in case component hasn't mounted
await nextTick();
}
if (refCruInnerForm.value && typeof refCruInnerForm.value.iniData === 'function') {
await refCruInnerForm.value.iniData(flowForm);
} else {
throw new Error('内嵌表单组件未就绪');
}
} else {
let formValues = resData.formValues || {};
let formUrlparval = formValues.dataId;
let formUrlpar = formValues.dataName || 'id';
const connector = flowForm.formUrl && flowForm.formUrl.includes('?') ? '&' : '?';
formUrl.value = (flowForm.formUrl || '') + connector + formUrlpar + '=' + formUrlparval;
// force iframe reload when src is set/changed
formKey.value++;
await nextTick();
console.error('表单url:', formUrl.value);
}
formError.value = false;
} catch (error) {
console.error('初始化表单失败:', error);
formError.value = true;
const msg = error instanceof Error ? error.message : String(error);
message.error(`表单加载失败: ${msg}`);
} finally {
formLoading.value = false;
}
};
const retryLoadForm = () => {
formError.value = false;
initializeCruInnerForm();
};
const refreshForm = () => {
formKey.value++;
initializeCruInnerForm();
};
const loadFlowRecord = async () => {
try {
loadingFlowRecord.value = true;
const { procInsId, deployId } = taskForm;
if (!procInsId || !deployId) return;
const res = await flowRecord({ procInsId, deployId });
flowRecordList.value = res.flowList || [];
} catch (error) {
console.error('加载流转记录失败:', error);
message.error('加载流转记录失败');
} finally {
loadingFlowRecord.value = false;
}
};
const loadFlowChart = async () => {
try {
loadingFlowChart.value = true;
const { procInsId, deployId } = taskForm;
if (!procInsId || !deployId) {
throw new Error('缺少流程实例信息');
}
const res = await flowXmlAndNode({ procInsId, deployId });
flowData.value = res;
} catch (error) {
console.error('加载流程图失败:', error);
message.error('加载流程图失败');
} finally {
loadingFlowChart.value = false;
}
};
const formatTime = (time: string) => {
if (!time) return '';
return dayjs(time).format('YYYY-MM-DD HH:mm:ss');
};
const formatDuration = (duration: string) => {
if (!duration) return '';
return duration.replace('PT', '').toLowerCase();
};
const getTimelineColor = (finishTime: string | null) => {
return finishTime ? 'green' : 'blue';
};
const getTaskStatusColor = (finishTime: string | null) => {
return finishTime ? 'success' : 'processing';
};
const handleSendTask = async () => {
if (sending.value) return;
try {
sending.value = true;
const submitData = {
instanceId: taskForm.instanceId,
deployId: taskForm.deployId,
taskId: taskForm.taskId,
comment: '',
values: {},
};
//找到选择的下一步节点
if (nextNodenum.value > 1) {
submitData.values['userTaskid'] = nextNodeNameSelevue.value;
}
if (!showApprovalUi.value) {
const result = await complete(submitData);
message.success('任务结束成功');
emit('success', result);
emit('callback');
return false;
}
const formData = await validate();
Object.assign(submitData, formData);
submitData.comment = submitData.comment || '';
//alert("dd"+isFixed.value);
// if (!isFixed.value) {
if (userType.value === 'user') {
submitData.values['approval'] = formData.checkSendUser;
submitData.values['copyUser'] = formData.copyUser;
submitData.values['approvalType'] = 'user';
if (formData.checkSendUser) {
submitData.values['approval'] = formData.checkSendUser;
submitData.values['copyUser'] = formData.copyUser;
submitData.values['approvalType'] = 'user';
}
} else if (formData.checkSendRole) {
submitData.values['approval'] = formData.checkSendRole;
submitData.values['approvalType'] = 'role';
}else{
submitData.values['approval'] = formData.checkSendUser;
submitData.values['copyUser'] = formData.copyUser;
submitData.values['approvalType'] = 'user';
}
console.log("ssss why ----",submitData);
const result = await complete(submitData);
message.success('任务发送成功');
emit('success', result);
emit('callback');
} catch (error: any) {
if (error.errorFields) {
message.error('请完善表单信息');
} else {
message.error(error.message || '发送任务失败');
}
} finally {
sending.value = false;
}
};
const handleReject = () => {
openRejectModal(true, {
isUpdate: false,
data: workFlowData.value,
onSuccess: () => {
message.error('任务已驳回');
emit('callback');
},
});
};
const onFlowChartLoaded = () => {
console.log('流程图加载完成');
};
const handleChange = (value: string) => {
console.log(`selected ${value}`);
nextNodeNameSelevue.value = value;
console.log(' nextNodeNameSelevue.value ', nextNodeNameSelevue.value);
if (value == 0) {
ChangeSelectNodeAfter(res0);
}
if (value == 1) {
ChangeSelectNodeAfter(res1);
}
if (value == 2) {
ChangeSelectNodeAfter(res2);
}
};
function ChangeSelectNodeAfter(res) {
isFixed.value = res.dataType == 'fixed' ? true : false;
if (isFixed.value && !isApproval.value) {
showApprovalUi.value;
}
nextNode.value = res;
nextNodeName.value = res.userTask?.name || '';
if (res.type === 'role') {
removeSchemaByFiled('checkSendUser');
if (res.dataType === 'fixed' && res.userTask?.candidateGroups) {
setFieldsValue({
checkSendRole: res.userTask.candidateGroups,
});
}
} else {
removeSchemaByFiled('checkSendRole');
if (res.dataType === 'fixed' && res.userTask?.assignee) {
setFieldsValue({
checkSendUser: res.userTask.assignee,
});
}
}
updateSchema([
{
field: 'checkSendUser',
label: isApproval.value ? '接收人' : '审批人',
componentProps: {
modalTitle: isApproval.value ? '选择接收人' : '选择审批人',
placeholder: isApproval.value ? '请选择接收人' : '请选择审批人',
},
},
]);
}
const iniData = async (data: any) => {
try {
// 设置工作流数据
workFlowData.value = data;
console.log('why iniData', data);
// 更新任务表单
Object.assign(taskForm, {
deployId: data.deployId || '',
taskId: data.taskId || '',
procInsId: data.procInsId || '',
executionId: data.executionId || '',
instanceId: data.procInsId || '',
});
isApproval.value = data.nodeisApprove;
nextTick(() => {
updateSchema([
{
field: 'checkSendUser',
label: isApproval.value ? '接收人' : '审批人',
componentProps: {
modalTitle: isApproval.value ? '选择接收人' : '选择审批人',
placeholder: isApproval.value ? '请选择接收人' : '请选择审批人',
},
},
]);
});
if (!isApproval.value) {
approvalTitle.value = '选择人员';
removeSchemaByFiled('comment');
} else {
approvalTitle.value = '填写意见';
}
if (taskForm.taskId) {
const reslist = await getNextFlowNode({ taskId: taskForm.taskId });
console.log('getNextFlowNode reslist ', reslist);
if (reslist == null) {
// 到达流程结束节点:设置展示状态但不要提前返回,仍需加载表单和流转记录
nextNodeName.value = '结束';
removeSchemaByFiled('checkSendRole');
removeSchemaByFiled('checkSendUser');
showApprovalUi.value = isApproval.value;
shownextNodeNameSele.value = false;
shownextNodeNametext.value = true;
// 不再 return,这样后续仍会继续加载流转记录和表单
} else {
shownextNodeNameSele.value = true;
shownextNodeNametext.value = false;
nextNodenum.value = reslist.length;
//why工作流修改
// 使用 for 循环赋值
for (let i = 0; i < reslist.length; i++) {
let resb = reslist[i];
tableOptions.value.push({
id: `${i}`,
name: `${resb.userTask.name}`,
value: `${i}`,
});
}
nextNodeNameSele.value = tableOptions.value[0].name;
const res = reslist[0]; // 获取第一行数据
console.log('res ', res);
ChangeSelectNodeAfter(res);
if (reslist.length == 1) {
res0.value = reslist[0];
}
if (reslist.length == 2) {
res0.value = reslist[0];
res1.value = reslist[1];
}
if (reslist.length == 3) {
res0.value = reslist[0];
res1.value = reslist[1];
res2.value = reslist[2];
}
}
}
// 加载流转记录
await loadFlowRecord();
// 加载当前表单
if (activeName.value === '1') {
await initializeCruInnerForm();
}
} catch (error) {
console.error('初始化数据失败:', error);
message.error('初始化失败,请刷新页面重试');
}
};
//转办处理
const handleAssignTask = () => {
openAssignModal(true, {
isUpdate: false,
data: workFlowData.value,
onSuccess: () => {
message.success('任务转办成功');
emit('success');
emit('callback');
},
});
};
//转阅处理
const handleAssignReadTask = () => {
openAssignReadModal(true, {
isUpdate: false,
data: workFlowData.value,
onSuccess: () => {
message.success('任务转阅成功');
emit('success');
emit('callback');
},
});
};
defineExpose({
iniData,
});
</script>
<style lang="scss" scoped>
/* ==================== 柔和中性风格 - CSS 变量 ==================== */
.execute-form-container {
background: var(--color-bg-white);
min-height: 100vh;
font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Helvetica Neue', sans-serif;
}
.app-container {
--color-primary: #3b5bdb;
--color-primary-hover: #364fc7;
--color-primary-light: #e8ecfd;
--color-success: #2f9e44;
--color-warning: #e67700;
--color-error: #c92a2a;
--color-text-primary: #1c1c1e;
--color-text-secondary: #555770;
--color-text-muted: #a0a3b1;
--color-border: #e4e4e9;
--color-border-strong: #c8c8d0;
--color-bg-page: #f5f5f7;
--color-bg-white: #ffffff;
--color-bg-section: #f0f0f4;
--radius: 6px;
height: 100vh;
margin: 0;
padding: 0;
// background: linear-gradient(135deg, #b0b3c2 0%, #764ba2 100%);
overflow: hidden;
}
.box-card {
height: 100%;
border: none;
box-shadow: none;
border-radius: 0;
overflow: hidden;
margin: 0px;
:deep(.ant-card-body) {
height: 100%;
padding: 0;
}
}
.process-tabs {
height: 100%;
:deep(.ant-tabs-nav) {
background: white;
margin: 0;
padding: 0 24px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
}
:deep(.ant-tabs-content) {
height: calc(100% - 55px);
overflow: hidden;
}
:deep(.ant-tabs-tabpane) {
height: 100%;
padding: 0;
}
}
// 当前表单页面样式
.form-container {
height: 100%;
display: flex;
flex-direction: column;
background: #f5f7fa;
}
.action-header {
background: white;
padding: 16px 24px;
display: flex;
justify-content: space-between;
align-items: center;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
border-bottom: 1px solid #f0f0f0;
.action-left {
flex: 1;
}
.action-right {
.next-node-info {
display: flex;
align-items: center;
gap: 12px;
}
.next-node-label {
width: 120px;
color: #666;
font-size: 14px;
}
.next-node-tag {
font-size: 14px;
padding: 4px 12px;
border-radius: 16px;
font-weight: 500;
}
}
}
.content-wrapper {
flex: 1;
display: flex;
gap: 24px;
padding: 24px;
overflow: hidden;
}
.main-form-section {
flex: 3;
min-width: 0;
.form-card {
height: 100%;
border-radius: 8px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
overflow: hidden;
:deep(.ant-card-head) {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
padding: 0 24px;
.ant-card-head-title {
font-size: 18px;
font-weight: 600;
padding: 16px 0;
}
.ant-card-extra {
padding: 16px 0;
button {
color: white;
&:hover {
color: rgba(255, 255, 255, 0.8);
}
}
}
}
:deep(.ant-card-body) {
padding: 24px;
height: calc(100% - 64px);
overflow-y: auto;
}
}
.loading-state,
.error-state {
display: flex;
justify-content: center;
align-items: center;
height: 400px;
}
.form-wrapper {
height: 100%;
}
}
.sidebar-section {
flex: 1;
min-width: 400px;
.approval-card {
height: 100%;
border-radius: 8px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
overflow: hidden;
:deep(.ant-card-head) {
background: linear-gradient(135deg, #36d1dc 0%, #5b86e5 100%);
color: white;
border: none;
padding: 0 24px;
.ant-card-head-title {
font-size: 18px;
font-weight: 600;
padding: 16px 0;
}
}
:deep(.ant-card-body) {
padding: 24px;
height: calc(100% - 64px);
display: flex;
flex-direction: column;
}
}
.form-tips {
margin-top: auto;
padding-top: 20px;
.tips-alert {
border-radius: 6px;
:deep(.ant-alert-message) {
font-weight: 500;
}
}
}
}
// 流转记录页面样式
.record-container {
height: 100%;
padding: 24px;
background: #f5f7fa;
.record-card {
height: 100%;
border-radius: 8px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
overflow: hidden;
:deep(.ant-card-head) {
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
color: white;
border: none;
padding: 0 24px;
.ant-card-head-title {
font-size: 18px;
font-weight: 600;
padding: 16px 0;
}
}
:deep(.ant-card-body) {
padding: 24px;
height: calc(100% - 64px);
overflow-y: auto;
}
}
.record-title {
display: flex;
align-items: center;
font-size: 16px;
.anticon {
font-size: 20px;
}
}
}
.flow-timeline {
:deep(.ant-timeline-item) {
padding-bottom: 24px;
&:last-child {
padding-bottom: 0;
}
}
}
.timeline-item {
.timeline-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
.task-name {
display: flex;
align-items: center;
gap: 12px;
.status-tag {
border-radius: 12px;
font-size: 12px;
padding: 2px 10px;
}
.task-title {
font-weight: 500;
color: #333;
}
}
.task-time {
color: #666;
font-size: 13px;
.anticon {
margin-right: 4px;
}
}
}
.timeline-content {
:deep(.ant-descriptions) {
border-radius: 6px;
overflow: hidden;
.ant-descriptions-item-label {
background: #fafafa;
font-weight: 500;
min-width: 80px;
}
.desc-icon {
margin-right: 8px;
color: #666;
}
}
}
.comment-box {
white-space: pre-wrap;
word-break: break-word;
line-height: 1.6;
color: #333;
}
}
.loading-state,
.empty-state {
display: flex;
justify-content: center;
align-items: center;
height: 300px;
}
// 流程图页面样式
.flowchart-container {
height: 100%;
padding: 24px;
background: #f5f7fa;
.flowchart-card {
height: 100%;
border-radius: 8px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
overflow: hidden;
:deep(.ant-card-head) {
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
color: white;
border: none;
padding: 0 24px;
.ant-card-head-title {
font-size: 18px;
font-weight: 600;
padding: 16px 0;
}
}
:deep(.ant-card-body) {
height: calc(100% - 64px);
padding: 0;
}
}
.flowchart-title {
display: flex;
align-items: center;
font-size: 16px;
.anticon {
font-size: 20px;
}
}
}
.bpmn-wrapper {
height: 100%;
padding: 24px;
.loading-state {
display: flex;
justify-content: center;
align-items: center;
height: 500px;
}
.bpmn-content {
height: 100%;
min-height: 500px;
border: 1px solid #e8e8e8;
border-radius: 6px;
overflow: hidden;
background: white;
}
}
// 响应式设计
@media (max-width: 1200px) {
.content-wrapper {
flex-direction: column;
gap: 20px;
}
.main-form-section,
.sidebar-section {
flex: none;
min-width: auto;
}
.sidebar-section {
min-height: 400px;
}
}
@media (max-width: 768px) {
.action-header {
flex-direction: column;
gap: 16px;
align-items: stretch;
.action-right {
.next-node-info {
justify-content: center;
}
}
}
.content-wrapper {
padding: 16px;
}
.process-tabs {
:deep(.ant-tabs-nav) {
padding: 0 16px;
}
}
}
// 滚动条美化
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 4px;
}
::-webkit-scrollbar-thumb {
background: #c1c1c1;
border-radius: 4px;
&:hover {
background: #a8a8a8;
}
}
// 动画效果
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
</style>
......@@ -40,7 +40,7 @@
class="custom-class"
root-class-name="root-class-name"
:root-style="{ color: 'blue' }"
title="待任务"
title="待任务"
placement="right"
width="90%"
style="margin: 0px; padding: 0px"
......
......@@ -44,7 +44,7 @@
<span class="tag">任务节点: {{ taskName }}</span>
</div>
</template>
<TodoIndex v-if="isShowDrawer" ref="refTodoIndex" @callback="handleSuccess" />
<TodoReadIndex v-if="isShowDrawer" ref="refTodoIndex" @callback="handleSuccess" />
</a-drawer>
</div>
......@@ -75,7 +75,7 @@
import { getDateByPicker } from '/@/utils';
import { todoList, getMyTaskFlow } from '/@/components/Process/api/todo';
// 引入待办任务组件
import TodoIndex from '../flowable/task/todo/components/TodoIndex.vue';
import TodoReadIndex from '../flowable/task/todo/components/TodoReadIndex.vue';
// 引入详情组件
import Detail from '../flowable/task/myProcess/components/Detail.vue';
const taskCache = new Map<string, any>();
......
......@@ -157,12 +157,14 @@ public class FlowInstanceServiceImpl extends FlowServiceFactory implements IFlow
HistoricProcessInstance historicProcessInstance = getHistoricProcessInstanceById(instanceId);
if (historicProcessInstance.getEndTime() != null) {
historyService.deleteHistoricProcessInstance(historicProcessInstance.getId());
return;
// return;
}else{
// 删除流程实例
runtimeService.deleteProcessInstance(instanceId, deleteReason);
// 删除历史流程实例
historyService.deleteHistoricProcessInstance(instanceId);
}
// 删除流程实例
runtimeService.deleteProcessInstance(instanceId, deleteReason);
// 删除历史流程实例
historyService.deleteHistoricProcessInstance(instanceId);
//删除业务数据
sysDeployFormService.deleteMyTaskFlowAndCCAndHis(instanceId);
......
......@@ -19,6 +19,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.modules.stm.utils.UserUtil;
import org.jeecgframework.poi.excel.ExcelImportUtil;
import org.jeecgframework.poi.excel.def.NormalExcelConstants;
import org.jeecgframework.poi.excel.entity.ExportParams;
......@@ -69,6 +70,7 @@ public class MyTaskFlowCcController extends JeecgController<MyTaskFlowCc, IMyTas
QueryWrapper<MyTaskFlowCc> queryWrapper = QueryGenerator.initQueryWrapper(myTaskFlowCc, req.getParameterMap());
Page<MyTaskFlowCc> page = new Page<MyTaskFlowCc>(pageNo, pageSize);
queryWrapper.eq("ccid", UserUtil.getUserId());
IPage<MyTaskFlowCc> pageList = myTaskFlowCcService.page(page, queryWrapper);
return Result.OK(pageList);
}
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论