<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>流程审批系统</title>
<!-- 引入Element Plus样式 -->
<link rel="stylesheet" href="https://unpkg.com/element-plus/dist/index.css">
<!-- 引入LogicFlow样式 -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@logicflow/core/lib/style/index.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@logicflow/extension/lib/style/index.css">
<!-- 引入Vue 3和Element Plus -->
<script src="https://unpkg.com/vue@3"></script>
<script src="https://unpkg.com/element-plus"></script>
<!-- 引入LogicFlow -->
<script src="https://cdn.jsdelivr.net/npm/@logicflow/core/dist/logic-flow.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@logicflow/extension/lib/index.js"></script>
<style>
:root {
--primary-color: #409EFF;
--success-color: #67C23A;
--warning-color: #E6A23C;
--danger-color: #F56C6C;
--info-color: #909399;
}
body {
margin: 0;
padding: 0;
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
background-color: #f5f7fa;
color: #303133;
}
.app-container {
display: flex;
flex-direction: column;
min-height: 100vh;
}
.header {
background-color: var(--primary-color);
color: white;
padding: 0 20px;
height: 60px;
display: flex;
align-items: center;
justify-content: space-between;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.main-content {
display: flex;
flex: 1;
}
.sidebar {
width: 220px;
background-color: #304156;
color: white;
height: calc(100vh - 60px);
overflow-y: auto;
}
.content {
flex: 1;
padding: 20px;
overflow-y: auto;
height: calc(100vh - 60px);
}
.page-title {
margin-bottom: 20px;
padding-bottom: 10px;
border-bottom: 1px solid #ebeef5;
}
.card-container {
background: white;
border-radius: 4px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
padding: 20px;
margin-bottom: 20px;
}
.toolbar {
margin-bottom: 20px;
display: flex;
justify-content: space-between;
align-items: center;
}
.logicflow-container {
height: 500px;
border: 1px solid #e0e0e0;
border-radius: 4px;
overflow: hidden;
}
.property-panel {
position: absolute;
right: 20px;
top: 100px;
width: 300px;
background: white;
border: 1px solid #e0e0e0;
border-radius: 4px;
padding: 15px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
z-index: 100;
}
.task-filter {
margin-bottom: 20px;
display: flex;
gap: 10px;
}
.task-item {
border-left: 4px solid var(--primary-color);
padding: 15px;
margin-bottom: 15px;
background: white;
border-radius: 4px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
.task-item.urgent {
border-left-color: var(--danger-color);
}
.task-item.completed {
border-left-color: var(--success-color);
}
.task-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
}
.task-title {
font-weight: bold;
font-size: 16px;
}
.task-meta {
color: var(--info-color);
font-size: 14px;
margin-bottom: 10px;
}
.task-actions {
display: flex;
gap: 10px;
}
.process-status {
display: inline-block;
padding: 5px 10px;
border-radius: 3px;
font-size: 12px;
color: white;
}
.status-pending {
background-color: var(--warning-color);
}
.status-approved {
background-color: var(--success-color);
}
.status-rejected {
background-color: var(--danger-color);
}
.status-processing {
background-color: var(--primary-color);
}
.menu-item {
padding: 15px 20px;
cursor: pointer;
transition: background-color 0.3s;
}
.menu-item:hover, .menu-item.active {
background-color: #263445;
}
.menu-item i {
margin-right: 10px;
}
</style>
</head>
<body>
<div id="app">
<div class="app-container">
<!-- 顶部导航栏 -->
<div class="header">
<h2>流程审批系统</h2>
<div>
<el-dropdown>
<span class="el-dropdown-link">
管理员 <i class="el-icon-arrow-down el-icon--right"></i>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item>个人信息</el-dropdown-item>
<el-dropdown-item>退出登录</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</div>
<div class="main-content">
<!-- 侧边栏菜单 -->
<div class="sidebar">
<div
v-for="item in menuItems"
:key="item.key"
:class="['menu-item', { active: activeMenu === item.key }]"
@click="activeMenu = item.key"
>
<i :class="item.icon"></i>
<span>{{ item.label }}</span>
</div>
</div>
<!-- 主内容区域 -->
<div class="content">
<!-- 流程设计器 -->
<div v-if="activeMenu === 'design'">
<h2 class="page-title">流程设计器</h2>
<div class="card-container">
<div class="toolbar">
<div>
<el-select v-model="currentTemplate" placeholder="选择流程模板" style="width: 200px;">
<el-option
v-for="template in templateList"
:key="template.id"
:label="template.name"
:value="template.id"
/>
</el-select>
<el-button type="primary" style="margin-left: 10px;" @click="saveFlow">保存流程</el-button>
<el-button @click="createNewTemplate">新建模板</el-button>
</div>
<div>
<el-button @click="importFlow">导入</el-button>
<el-button @click="exportFlow">导出</el-button>
</div>
</div>
<div class="logicflow-container" ref="container"></div>
<!-- 节点属性面板 -->
<div v-if="selectedNode" class="property-panel">
<h3>节点属性</h3>
<el-form label-width="80px">
<el-form-item label="节点名称">
<el-input v-model="selectedNode.properties.name"></el-input>
</el-form-item>
<el-form-item v-if="selectedNode.type === 'approval'" label="审批人">
<el-select v-model="selectedNode.properties.approver" multiple placeholder="选择审批人">
<el-option v-for="user in userList" :key="user.id" :label="user.name" :value="user.id"></el-option>
</el-select>
</el-form-item>
<el-form-item v-if="selectedNode.type === 'condition'" label="条件表达式">
<el-input v-model="selectedNode.properties.condition" type="textarea" :rows="2"></el-input>
</el-form-item>
<el-form-item label="描述信息">
<el-input v-model="selectedNode.properties.desc" type="textarea" :rows="2"></el-input>
</el-form-item>
</el-form>
</div>
</div>
</div>
<!-- 我的任务 -->
<div v-if="activeMenu === 'tasks'">
<h2 class="page-title">我的任务</h2>
<div class="card-container">
<div class="task-filter">
<el-radio-group v-model="taskFilter">
<el-radio-button label="pending">待我审批</el-radio-button>
<el-radio-button label="processed">我已审批</el-radio-button>
<el-radio-button label="started">我发起的</el-radio-button>
</el-radio-group>
<el-input placeholder="搜索流程名称" style="width: 200px;" v-model="searchKeyword">
<template #append>
<el-button icon="el-icon-search"></el-button>
</template>
</el-input>
</div>
<div v-if="filteredTasks.length > 0">
<div
v-for="task in filteredTasks"
:key="task.id"
:class="['task-item', { urgent: task.priority === 'high', completed: task.status === 'completed' }]"
>
<div class="task-header">
<div class="task-title">{{ task.processName }}</div>
<div>
<span :class="['process-status', `status-${task.status}`]">
{{ taskStatusMap[task.status] }}
</span>
</div>
</div>
<div class="task-meta">
<div>申请人: {{ task.applicant }} | 申请时间: {{ task.applyTime }}</div>
<div>当前节点: {{ task.currentNode }}</div>
<div v-if="task.comment">审批意见: {{ task.comment }}</div>
</div>
<div class="task-actions">
<el-button
v-if="task.status === 'pending'"
type="primary"
size="small"
@click="handleApprove(task)"
>审批</el-button>
<el-button
v-if="task.status === 'pending'"
type="danger"
size="small"
@click="handleReject(task)"
>驳回</el-button>
<el-button
v-if="task.status === 'pending'"
type="warning"
size="small"
@click="handleTransfer(task)"
>转办</el-button>
<el-button
size="small"
@click="viewProcess(task)"
>查看进度</el-button>
</div>
</div>
</div>
<el-empty v-else description="暂无任务"></el-empty>
</div>
</div>
<!-- 新建流程 -->
<div v-if="activeMenu === 'create'">
<h2 class="page-title">新建流程申请</h2>
<div class="card-container">
<el-form :model="formData" :rules="formRules" ref="applyForm" label-width="120px">
<!-- 流程模板选择 -->
<el-form-item label="流程模板" prop="templateId">
<el-select v-model="formData.templateId" placeholder="请选择流程模板" @change="handleTemplateChange">
<el-option
v-for="template in templateList"
:key="template.id"
:label="template.name"
:value="template.id"
>
<span style="float: left">{{ template.name }}</span>
<span style="float: right; color: #8492a6; font-size: 13px">
{{ template.category }}
</span>
</el-option>
</el-select>
</el-form-item>
<!-- 动态表单区域 -->
<div v-if="selectedTemplate">
<el-divider content-position="left">申请信息</el-divider>
<div v-for="field in selectedTemplate.fields" :key="field.name">
<el-form-item
:label="field.label"
:prop="'fields.' + field.name"
:rules="field.rules"
>
<el-input
v-if="field.type === 'text' || field.type === 'textarea'"
v-model="formData.fields[field.name]"
:type="field.type"
:rows="field.type === 'textarea' ? 4 : 2"
:placeholder="'请输入' + field.label"
/>
<el-input-number
v-else-if="field.type === 'number'"
v-model="formData.fields[field.name]"
:placeholder="'请输入' + field.label"
/>
<el-date-picker
v-else-if="field.type === 'date' || field.type === 'datetime'"
v-model="formData.fields[field.name]"
:type="field.type"
:placeholder="'请选择' + field.label"
style="width: 100%"
/>
<el-select
v-else-if="field.type === 'select'"
v-model="formData.fields[field.name]"
:placeholder="'请选择' + field.label"
style="width: 100%"
>
<el-option
v-for="option in field.options"
:key="option.value"
:label="option.label"
:value="option.value"
/>
</el-select>
</el-form-item>
</div>
<el-divider content-position="left">附件材料</el-divider>
<el-upload
action="#"
:auto-upload="false"
:on-change="handleFileChange"
:on-remove="handleFileRemove"
:file-list="fileList"
multiple
>
<el-button type="primary">点击上传</el-button>
<template #tip>
<div class="el-upload__tip">
支持扩展名:.doc .docx .pdf .jpg .png,单个文件不超过10MB
</div>
</template>
</el-upload>
<div v-if="fileList.length > 0" style="margin-top: 15px;">
<div v-for="(file, index) in fileList" :key="index" style="display: flex; align-items: center; justify-content: space-between; padding: 8px; background-color: #f5f7fa; margin-bottom: 8px; border-radius: 4px;">
<div style="display: flex; align-items: center;">
<el-icon><Document /></el-icon>
<span style="margin-left: 8px">{{ file.name }}</span>
</div>
<el-button size="small" type="danger" text @click="handleFileRemove(file)">删除</el-button>
</div>
</div>
<el-divider content-position="left">审批流程</el-divider>
<el-timeline>
<el-timeline-item
v-for="(approver, index) in selectedTemplate.approvers"
:key="index"
:timestamp="'第' + (index + 1) + '步'"
placement="top"
>
<el-card>
<h4>{{ approver.nodeName }}</h4>
<p>审批人: {{ approver.userName }}</p>
<p v-if="approver.description">{{ approver.description }}</p>
</el-card>
</el-timeline-item>
</el-timeline>
</div>
<!-- 操作按钮 -->
<el-form-item style="margin-top: 30px;">
<el-button type="primary" @click="submitForm" :loading="submitting">提交申请</el-button>
<el-button @click="resetForm">重置</el-button>
</el-form-item>
</el-form>
</div>
</div>
<!-- 流程监控 -->
<div v-if="activeMenu === 'monitor'">
<h2 class="page-title">流程监控</h2>
<div class="card-container">
<el-table :data="processInstances" style="width: 100%">
<el-table-column prop="name" label="流程名称" width="180"></el-table-column>
<el-table-column prop="applicant" label="申请人" width="120"></el-table-column>
<el-table-column prop="startTime" label="开始时间" width="150"></el-table-column>
<el-table-column prop="currentNode" label="当前节点" width="120"></el-table-column>
<el-table-column label="状态" width="100">
<template #default="scope">
<el-tag :type="statusType(scope.row.status)">
{{ scope.row.status }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="150">
<template #default="scope">
<el-button size="small" @click="viewProcessDetail(scope.row)">查看详情</el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
</div>
</div>
</div>
<!-- 审批对话框 -->
<el-dialog :title="dialogTitle" v-model="approvalDialogVisible" width="500px">
<el-form :model="approvalForm" label-width="80px">
<el-form-item label="审批意见">
<el-input v-model="approvalForm.comment" type="textarea" :rows="3"></el-input>
</el-form-item>
<el-form-item v-if="dialogType === 'transfer'" label="转办给">
<el-select v-model="approvalForm.transferTo" placeholder="选择转办人">
<el-option v-for="user in userList" :key="user.id" :label="user.name" :value="user.id"></el-option>
</el-select>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="approvalDialogVisible = false">取消</el-button>
<el-button
v-if="dialogType === 'approve'"
type="primary"
@click="confirmApprove"
>通过</el-button>
<el-button
v-if="dialogType === 'reject'"
type="danger"
@click="confirmReject"
>驳回</el-button>
<el-button
v-if="dialogType === 'transfer'"
type="warning"
@click="confirmTransfer"
>确认转办</el-button>
</template>
</el-dialog>
</div>
<script>
const { createApp, ref, reactive, computed, onMounted } = Vue;
createApp({
setup() {
// 菜单项
const menuItems = reactive([
{ key: 'design', label: '流程设计', icon: 'el-icon-s-promotion' },
{ key: 'tasks', label: '我的任务', icon: 'el-icon-tickets' },
{ key: 'create', label: '新建流程', icon: 'el-icon-circle-plus-outline' },
{ key: 'monitor', label: '流程监控', icon: 'el-icon-data-line' }
]);
const activeMenu = ref('tasks');
// LogicFlow相关
const container = ref(null);
let lf = null;
const selectedNode = ref(null);
const currentTemplate = ref('');
// 模板列表
const templateList = ref([
{
id: 1,
name: '请假申请',
category: '人力资源',
description: '用于员工请假申请审批流程',
fields: [
{
name: 'leaveType',
label: '请假类型',
type: 'select',
rules: [{ required: true, message: '请选择请假类型', trigger: 'change' }],
options: [
{ value: 'annual', label: '年假' },
{ value: 'sick', label: '病假' },
{ value: 'personal', label: '事假' },
{ value: 'marriage', label: '婚假' },
{ value: 'maternity', label: '产假' }
]
},
{
name: 'startDate',
label: '开始时间',
type: 'datetime',
rules: [{ required: true, message: '请选择开始时间', trigger: 'change' }]
},
{
name: 'endDate',
label: '结束时间',
type: 'datetime',
rules: [{ required: true, message: '请选择结束时间', trigger: 'change' }]
},
{
name: 'duration',
label: '请假时长(天)',
type: 'number',
rules: [
{ required: true, message: '请输入请假时长', trigger: 'blur' },
{ type: 'number', min: 0.5, max: 365, message: '时长应在0.5到365天之间', trigger: 'blur' }
]
},
{
name: 'reason',
label: '请假事由',
type: 'textarea',
rules: [{ required: true, message: '请输入请假事由', trigger: 'blur' }]
}
],
approvers: [
{ nodeName: '直属上级审批', userName: '张经理', description: '审批请假合理性' },
{ nodeName: '人事部门审核', userName: '李人事', description: '核对假期余额及合规性' }
]
},
{
id: 2,
name: '采购申请',
category: '财务',
description: '用于物品采购申请审批流程',
fields: [
{
name: 'itemName',
label: '物品名称',
type: 'text',
rules: [{ required: true, message: '请输入物品名称', trigger: 'blur' }]
},
{
name: 'specification',
label: '规格型号',
type: 'text',
rules: [{ required: true, message: '请输入规格型号', trigger: 'blur' }]
},
{
name: 'quantity',
label: '数量',
type: 'number',
rules: [
{ required: true, message: '请输入数量', trigger: 'blur' },
{ type: 'number', min: 1, message: '数量必须大于0', trigger: 'blur' }
]
},
{
name: 'estimatedPrice',
label: '预估单价',
type: 'number',
rules: [
{ required: true, message: '请输入预估单价', trigger: 'blur' },
{ type: 'number', min: 0, message: '单价不能为负数', trigger: 'blur' }
]
},
{
name: 'purpose',
label: '用途说明',
type: 'textarea',
rules: [{ required: true, message: '请输入用途说明', trigger: 'blur' }]
}
],
approvers: [
{ nodeName: '部门经理审批', userName: '王经理', description: '审核采购必要性' },
{ nodeName: '财务审核', userName: '赵会计', description: '审核预算及价格合理性' },
{ nodeName: '总经理审批', userName: '孙总', description: '最终审批' }
]
}
]);
// 用户列表
const userList = ref([
{ id: 1, name: '张三', department: '技术部' },
{ id: 2, name: '李四', department: '人事部' },
{ id: 3, name: '王五', department: '财务部' },
{ id: 4, name: '赵六', department: '市场部' },
{ id: 5, name: '钱七', department: '技术部' }
]);
// 初始化LogicFlow
const initLogicFlow = () => {
if (!container.value) return;
// 使用LogicFlow的BPMN扩展
LogicFlow.use(LogicFlow.BpmnElement);
LogicFlow.use(LogicFlow.Snapshot);
LogicFlow.use(LogicFlow.Menu);
LogicFlow.use(LogicFlow.Control);
lf = new LogicFlow({
container: container.value,
grid: true,
width: container.value.clientWidth,
height: 500,
keyboard: { enabled: true },
style: {
rect: {
width: 100,
height: 60,
radius: 6
}
}
});
// 渲染初始流程图
lf.render({
nodes: [
{
id: '1',
type: 'bpmn:startEvent',
x: 100,
y: 100,
properties: {
name: '开始'
}
}
]
});
// 监听节点选择事件
lf.on('node:click', ({ data }) => {
selectedNode.value = data;
});
// 监听画布点击事件(点击空白处取消选择)
lf.on('blank:click', () => {
selectedNode.value = null;
});
};
// 保存流程
const saveFlow = () => {
if (!currentTemplate.value) {
ElMessage.warning('请先选择或创建流程模板');
return;
}
const graphData = lf.getGraphData();
console.log('保存流程数据:', graphData);
// 这里应该调用API保存流程数据
ElMessage.success('流程保存成功');
};
// 新建模板
const createNewTemplate = () => {
ElMessageBox.prompt('请输入新模板名称', '新建模板', {
confirmButtonText: '确定',
cancelButtonText: '取消',
}).then(({ value }) => {
if (!value) return;
const newTemplate = {
id: templateList.value.length + 1,
name: value,
category: '自定义',
description: '新建的流程模板',
fields: [],
approvers: []
};
templateList.value.push(newTemplate);
currentTemplate.value = newTemplate.id;
ElMessage.success('模板创建成功');
});
};
// 导入导出
const importFlow = () => {
ElMessage.info('导入功能');
};
const exportFlow = () => {
const graphData = lf.getGraphData();
const dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(graphData, null, 2));
const downloadAnchorNode = document.createElement('a');
downloadAnchorNode.setAttribute("href", dataStr);
downloadAnchorNode.setAttribute("download", "flow.json");
document.body.appendChild(downloadAnchorNode);
downloadAnchorNode.click();
downloadAnchorNode.remove();
ElMessage.success('流程已导出');
};
// 任务相关
const taskFilter = ref('pending');
const searchKeyword = ref('');
// 模拟任务数据
const tasks = ref([
{
id: 1,
processName: '请假申请',
applicant: '张三',
applyTime: '2023-10-01 09:30',
currentNode: '部门审批',
status: 'pending',
priority: 'normal',
comment: ''
},
{
id: 2,
processName: '采购申请',
applicant: '李四',
applyTime: '2023-10-01 10:15',
currentNode: '财务审核',
status: 'pending',
priority: 'high',
comment: ''
},
{
id: 3,
processName: '费用报销',
applicant: '王五',
applyTime: '2023-09-30 14:20',
currentNode: '已完成',
status: 'completed',
priority: 'normal',
comment: '符合公司报销政策'
}
]);
// 任务状态映射
const taskStatusMap = {
'pending': '待处理',
'processing': '处理中',
'completed': '已完成',
'rejected': '已驳回'
};
// 过滤后的任务列表
const filteredTasks = computed(() => {
let result = tasks.value;
// 根据筛选条件过滤
if (taskFilter.value === 'pending') {
result = result.filter(task => task.status === 'pending');
} else if (taskFilter.value === 'processed') {
result = result.filter(task => task.status === 'completed' || task.status === 'rejected');
} else if (taskFilter.value === 'started') {
// 这里应该是用户自己发起的流程
result = result.filter(task => task.applicant === '当前用户');
}
// 根据关键词搜索
if (searchKeyword.value) {
const keyword = searchKeyword.value.toLowerCase();
result = result.filter(task =>
task.processName.toLowerCase().includes(keyword) ||
task.applicant.toLowerCase().includes(keyword)
);
}
return result;
});
// 审批对话框相关
const approvalDialogVisible = ref(false);
const dialogType = ref(''); // approve, reject, transfer
const dialogTitle = ref('');
const currentTask = ref(null);
const approvalForm = reactive({
comment: '',
transferTo: ''
});
// 打开审批对话框
const handleApprove = (task) => {
currentTask.value = task;
dialogType.value = 'approve';
dialogTitle.value = `审批通过 - ${task.processName}`;
approvalForm.comment = '';
approvalDialogVisible.value = true;
};
// 打开驳回对话框
const handleReject = (task) => {
currentTask.value = task;
dialogType.value = 'reject';
dialogTitle.value = `驳回申请 - ${task.processName}`;
approvalForm.comment = '';
approvalDialogVisible.value = true;
};
// 打开转办对话框
const handleTransfer = (task) => {
currentTask.value = task;
dialogType.value = 'transfer';
dialogTitle.value = `转办任务 - ${task.processName}`;
approvalForm.comment = '';
approvalForm.transferTo = '';
approvalDialogVisible.value = true;
};
// 确认审批通过
const confirmApprove = () => {
if (!approvalForm.comment) {
ElMessage.warning('请填写审批意见');
return;
}
// 更新任务状态
const task = tasks.value.find(t => t.id === currentTask.value.id);
if (task) {
task.status = 'completed';
task.comment = approvalForm.comment;
}
approvalDialogVisible.value = false;
ElMessage.success('审批通过');
};
// 确认驳回
const confirmReject = () => {
if (!approvalForm.comment) {
ElMessage.warning('请填写驳回原因');
return;
}
// 更新任务状态
const task = tasks.value.find(t => t.id === currentTask.value.id);
if (task) {
task.status = 'rejected';
task.comment = approvalForm.comment;
}
approvalDialogVisible.value = false;
ElMessage.warning('申请已驳回');
};
// 确认转办
const confirmTransfer = () => {
if (!approvalForm.transferTo) {
ElMessage.warning('请选择转办人');
return;
}
// 查找转办人
const transferToUser = userList.value.find(user => user.id === approvalForm.transferTo);
if (!transferToUser) {
ElMessage.error('选择的转办人不存在');
return;
}
// 更新任务
const task = tasks.value.find(t => t.id === currentTask.value.id);
if (task) {
task.comment = `转办给: ${transferToUser.name}` + (approvalForm.comment ? `, 备注: ${approvalForm.comment}` : '');
// 在实际应用中,这里应该将任务转交给其他用户
}
approvalDialogVisible.value = false;
ElMessage.success(`任务已转办给 ${transferToUser.name}`);
};
// 查看流程进度
const viewProcess = (task) => {
ElMessage.info(`查看流程 ${task.processName} 的进度`);
// 这里应该打开流程进度详情页面
};
// 新建流程相关
const formData = reactive({
templateId: '',
fields: {}
});
const fileList = ref([]);
const submitting = ref(false);
const applyForm = ref(null);
// 当前选中的模板
const selectedTemplate = computed(() => {
return templateList.value.find(t => t.id === formData.templateId) || null;
});
// 表单验证规则
const formRules = reactive({
templateId: [
{ required: true, message: '请选择流程模板', trigger: 'change' }
]
});
// 处理模板选择变化
const handleTemplateChange = (templateId) => {
// 重置表单字段
formData.fields = {};
// 为选中模板的每个字段初始化值
if (selectedTemplate.value) {
selectedTemplate.value.fields.forEach(field => {
formData.fields[field.name] = field.type === 'number' ? 0 : '';
});
}
};
// 处理文件变化
const handleFileChange = (file, files) => {
// 限制文件大小
if (file.size > 10 * 1024 * 1024) {
ElMessage.error('文件大小不能超过10MB');
return false;
}
// 更新文件列表
fileList.value = files;
};
// 处理文件移除
const handleFileRemove = (file) => {
const index = fileList.value.indexOf(file);
if (index !== -1) {
fileList.value.splice(index, 1);
}
};
// 提交表单
const submitForm = () => {
if (!applyForm.value) return;
applyForm.value.validate((valid) => {
if (valid) {
submitting.value = true;
// 模拟API调用
setTimeout(() => {
ElMessage.success('申请提交成功!');
submitting.value = false;
// 重置表单
resetForm();
// 切换到任务页面
activeMenu.value = 'tasks';
}, 1500);
} else {
ElMessage.error('请完善表单信息');
return false;
}
});
};
// 重置表单
const resetForm = () => {
if (applyForm.value) {
applyForm.value.resetFields();
}
formData.fields = {};
fileList.value = [];
};
// 流程监控相关
const processInstances = ref([
{
id: 1,
name: '请假申请',
applicant: '张三',
startTime: '2023-10-01 09:30',
currentNode: '部门审批',
status: '审批中'
},
{
id: 2,
name: '采购申请',
applicant: '李四',
startTime: '2023-10-01 10:15',
currentNode: '财务审核',
status: '审批中'
},
{
id: 3,
name: '费用报销',
applicant: '王五',
startTime: '2023-09-30 14:20',
currentNode: '已完成',
status: '已通过'
}
]);
// 状态标签类型
const statusType = (status) => {
const map = {
'审批中': 'primary',
'已通过': 'success',
'已拒绝': 'danger',
'已撤销': 'info'
};
return map[status] || 'info';
};
// 查看流程详情
const viewProcessDetail = (process) => {
ElMessage.info(`查看流程 ${process.name} 的详情`);
// 这里应该打开流程详情页面
};
// 初始化
onMounted(() => {
initLogicFlow();
});
return {
menuItems,
activeMenu,
container,
selectedNode,
currentTemplate,
templateList,
userList,
saveFlow,
createNewTemplate,
importFlow,
exportFlow,
taskFilter,
searchKeyword,
filteredTasks,
taskStatusMap,
handleApprove,
handleReject,
handleTransfer,
viewProcess,
approvalDialogVisible,
dialogType,
dialogTitle,
approvalForm,
confirmApprove,
confirmReject,
confirmTransfer,
formData,
formRules,
fileList,
submitting,
applyForm,
selectedTemplate,
handleTemplateChange,
handleFileChange,
handleFileRemove,
submitForm,
resetForm,
processInstances,
statusType,
viewProcessDetail
};
}
}).use(ElementPlus).mount('#app');
</script>
</body>
</html>优化页面
最新发布