c7cdec27e0
commita514bf4009Author: 浅念 <email@sample.com> Date: Thu Sep 18 09:55:10 2025 +0800 Squashed commit of the following: commit9e260ddcd8Author: 浅念 <email@sample.com> Date: Thu Sep 18 09:49:33 2025 +0800 修改 kpi commit6feb3ace75Author: 浅念 <email@sample.com> Date: Thu Sep 18 09:42:44 2025 +0800 kpi 统计 commitec257a246dAuthor: 浅念 <email@sample.com> Date: Wed Sep 17 17:04:35 2025 +0800 修改 弹框表格 commitfa764852abAuthor: 浅念 <email@sample.com> Date: Wed Sep 17 15:54:35 2025 +0800 添加 账户简称 commit65f7f4a123Author: 浅念 <email@sample.com> Date: Wed Sep 17 15:10:28 2025 +0800 品牌加热门 修改 仪表盘接口 commit922cfec81dAuthor: 浅念 <email@sample.com> Date: Tue Sep 16 15:57:17 2025 +0800 调整备货单 crm 端页面 commit5c8df36f12Author: 浅念 <email@sample.com> Date: Mon Sep 15 17:14:38 2025 +0800 调整备货单 及各页面名称 commit5503a14408Author: 浅念 <email@sample.com> Date: Fri Sep 12 18:10:03 2025 +0800 账户添加公司 commit3439b45d9aAuthor: 浅念 <email@sample.com> Date: Fri Sep 12 17:53:26 2025 +0800 修改终版备货单 commit045d13eb7bAuthor: 浅念 <email@sample.com> Date: Fri Sep 12 17:49:07 2025 +0800 修改备货单 等页面 commitda690dfa06Author: 浅念 <email@sample.com> Date: Thu Sep 11 17:44:37 2025 +0800 修改 备货单 详情 commit853e9591b3Author: 浅念 <email@sample.com> Date: Wed Sep 10 18:11:39 2025 +0800 修改 备货单页面 commit9052bd1027Author: 浅念 <email@sample.com> Date: Tue Sep 9 20:53:30 2025 +0800 备货单 审核功能 commit079d9babb8Merge:ebd747991d810bAuthor: 浅念 <email@sample.com> Date: Tue Sep 9 14:51:43 2025 +0800 Merge branch 'feature/crm_pc' of http://219.157.255.213:25311/xinyouhe/art-design into feature/crm_vehicle commitebd7479573Merge:64e53b6459d306Author: 浅念 <email@sample.com> Date: Tue Sep 9 13:57:28 2025 +0800 Merge branch 'feature/crm_pc' of http://219.157.255.213:25311/xinyouhe/art-design into feature/crm_vehicle commit64e53b6ee9Author: 浅念 <email@sample.com> Date: Mon Sep 8 19:09:55 2025 +0800 备货单 加 审批流程 commit9bd7c89cb4Author: 浅念 <email@sample.com> Date: Thu Sep 4 15:09:17 2025 +0800 车辆信息,备货单 等页面 commit91d810b33aAuthor: 浅念 <email@sample.com> Date: Tue Sep 9 14:51:23 2025 +0800 添加公司搜索 commit459d306504Author: 浅念 <email@sample.com> Date: Tue Sep 9 13:56:43 2025 +0800 用户添加 公司搜索 commit8a0d4fc516Author: 浅念 <email@sample.com> Date: Thu Sep 4 14:38:09 2025 +0800 自定义跟进时间 处理 commit58f7d56f40Author: 浅念 <email@sample.com> Date: Wed Sep 3 15:13:10 2025 +0800 工单去掉 移动端不显示限制 commita91e1d7820Author: 浅念 <email@sample.com> Date: Tue Sep 2 14:13:15 2025 +0800 将编号 后移 commita9f8c5c4dcAuthor: 浅念 <email@sample.com> Date: Wed Aug 27 09:20:56 2025 +0800 客户重复通知 commitaefd43f79dAuthor: 浅念 <email@sample.com> Date: Tue Aug 26 09:55:42 2025 +0800 修改 通知详情样式 和 即时通讯 commit1bd9d163ecAuthor: 浅念 <email@sample.com> Date: Mon Aug 25 15:31:14 2025 +0800 通知 列表富文本内容显示 commitbe6093e57dAuthor: 浅念 <email@sample.com> Date: Mon Aug 25 13:34:13 2025 +0800 crm 客户添加自定义列 跟进添加图片粘贴上传 commitd83246ba8cAuthor: 浅念 <email@sample.com> Date: Fri Aug 22 18:33:58 2025 +0800 显示编号 commit329acaf68dAuthor: 浅念 <email@sample.com> Date: Fri Aug 22 18:27:26 2025 +0800 通知板块 及 功能调整 commitb319944007Author: 浅念 <email@sample.com> Date: Thu Aug 21 11:12:12 2025 +0800 调整联系方式字段为电话 列表中多个联系方式纵向排列显示 会增加公司信息的自定义输入框 排序搜索 等功能 commit70d26f0829Author: 浅念 <email@sample.com> Date: Tue Aug 19 16:18:15 2025 +0800 1.0.3 的相关功能 commit0e84bedb67Author: 浅念 <email@sample.com> Date: Fri Aug 15 16:31:55 2025 +0800 v1.0.2 更新内容 commitf5deb7b8f7Author: 浅念 <email@sample.com> Date: Wed Aug 13 19:27:49 2025 +0800 添加菜单 权限 等页面 commite797cb24deAuthor: 浅念 <email@sample.com> Date: Mon Aug 11 19:24:24 2025 +0800 添加工单附件 及样式 commit619311dfbeAuthor: chenlan <suya123456> Date: Fri Aug 8 22:13:25 2025 +0800 添加crm 归属客户 commitb402e522bfAuthor: 浅念 <email@sample.com> Date: Thu Aug 7 10:51:17 2025 +0800 询单权限校验 commitf950f665a9Author: 浅念 <email@sample.com> Date: Thu Aug 7 10:10:45 2025 +0800 添加 询单图片预览 commit8deecc8197Author: 浅念 <email@sample.com> Date: Wed Aug 6 18:36:42 2025 +0800 修改用户页面 询单 commit3e24d1905fAuthor: 浅念 <email@sample.com> Date: Tue Aug 5 18:25:32 2025 +0800 添加用户页面 客户页面接口 等 commit7542d80e38Author: 浅念 <email@sample.com> Date: Mon Aug 4 18:05:07 2025 +0800 修改 仪表盘页面样式 commite5548f95e4Author: 浅念 <email@sample.com> Date: Mon Aug 4 14:50:55 2025 +0800 修改询单字段 仪表盘页面 及添加管理端客户页面 commitd30ea5b7bfAuthor: 浅念 <email@sample.com> Date: Mon Aug 4 14:48:58 2025 +0800 添加echarts 插件 commit0e4160c5caAuthor: 浅念 <email@sample.com> Date: Fri Aug 1 18:27:22 2025 +0800 仪表盘接口 commitbd23288acdAuthor: 浅念 <email@sample.com> Date: Fri Aug 1 18:26:46 2025 +0800 修改 仪表盘 commit6bfb940881Author: 浅念 <email@sample.com> Date: Fri Aug 1 10:01:35 2025 +0800 客户列表 添加公海详情展示 commitb50f650565Author: 浅念 <email@sample.com> Date: Thu Jul 31 17:26:36 2025 +0800 修改 客户标签样式 个人信息添加邮箱 修复关闭全部页面404 commitea1dbb7af4Author: 浅念 <email@sample.com> Date: Wed Jul 30 18:50:31 2025 +0800 修改公海和询单页面 commit1bfbb95bd9Author: 浅念 <email@sample.com> Date: Wed Jul 30 17:23:09 2025 +0800 修改样式和添加用户数据显示 commita9f5f76b35Author: 浅念 <email@sample.com> Date: Wed Jul 30 15:06:03 2025 +0800 设置默认页面 commit3ea9d3d5dfAuthor: 浅念 <email@sample.com> Date: Wed Jul 30 11:46:31 2025 +0800 修改飞书登录 公司id 系统id 获取不到问题 客户及公海添加用户信息显示 commit0cef82279fAuthor: 浅念 <email@sample.com> Date: Tue Jul 29 16:42:36 2025 +0800 修改工单 客户等页面 commit695ebbcc71Author: 浅念 <email@sample.com> Date: Fri Jul 25 17:50:04 2025 +0800 修改默认值 commitffc194a1c1Author: 浅念 <email@sample.com> Date: Fri Jul 25 17:05:33 2025 +0800 飞书授权添加系统码 及登录进入页面路由 commit48b95e252fAuthor: 浅念 <email@sample.com> Date: Fri Jul 25 15:48:49 2025 +0800 回收站添加占位 commit382011d592Author: 浅念 <email@sample.com> Date: Fri Jul 25 15:11:50 2025 +0800 修改登录页样式公海数据 个人信息默认图 commit0f790269dbAuthor: 浅念 <email@sample.com> Date: Fri Jul 25 09:16:55 2025 +0800 修改字段名称 commitf18cfdb69eAuthor: 浅念 <email@sample.com> Date: Thu Jul 24 17:28:51 2025 +0800 调整代码格式 commit858147fbbdAuthor: 浅念 <email@sample.com> Date: Thu Jul 24 10:17:22 2025 +0800 修改token刷新 及修改询单详情展示 commitc333b907e6Author: 浅念 <email@sample.com> Date: Wed Jul 23 18:22:56 2025 +0800 对接询单接口 commit7979a31e36Author: 浅念 <email@sample.com> Date: Wed Jul 23 14:40:02 2025 +0800 修改代码格式 commit4a39387865Author: 浅念 <email@sample.com> Date: Wed Jul 23 14:07:13 2025 +0800 设置客户列表权限 commitfc4de02582Author: 浅念 <email@sample.com> Date: Tue Jul 22 17:08:13 2025 +0800 feat(router): 调整菜单 commit2ffe0c9753Author: 浅念 <email@sample.com> Date: Tue Jul 22 17:04:16 2025 +0800 feat(crmApi.ts): 调整结构 commitc3fb2c48d3Author: 浅念 <email@sample.com> Date: Tue Jul 22 17:00:25 2025 +0800 feat(router): 路由调整 commitc5b0a8265aAuthor: 浅念 <email@sample.com> Date: Tue Jul 22 16:54:06 2025 +0800 chore: 添加询单页面及调整菜单 commitca06c9bc46Author: 浅念 <email@sample.com> Date: Tue Jul 22 16:35:43 2025 +0800 询单页面及菜单 commit3b6de4c7faMerge:d3bb4ec85e8b9bAuthor: 浅念 <email@sample.com> Date: Tue Jul 22 09:22:20 2025 +0800 Merge branch 'master' into feature/crm_pc commitd3bb4ec6e5Merge:c7d8908d7ab6f1Author: 浅念 <email@sample.com> Date: Mon Jul 21 18:22:55 2025 +0800 Merge branch 'master' into feature/crm_pc # Conflicts: # .gitignore # src/api/crmApi.ts # src/api/usersApi.ts # src/store/modules/user.ts # src/utils/http/index.ts # src/views/auth/login/index.vue # src/views/crmpc/customer/Show.vue # src/views/crmpc/customer/index.vue commitc7d890809cAuthor: 浅念 <email@sample.com> Date: Mon Jul 21 18:12:16 2025 +0800 添加系统码 commit31cd18fadeAuthor: 浅念 <email@sample.com> Date: Mon Jul 21 18:02:48 2025 +0800 Merge branch 'master' into feature/crm_pc # Conflicts: # .gitignore commit59c9c97c08Author: 浅念 <email@sample.com> Date: Mon Jul 21 17:56:52 2025 +0800 Merge branch 'master' into feature/crm_pc # Conflicts: # .gitignore commitd4b577c42eAuthor: 浅念 <email@sample.com> Date: Mon Jul 21 13:03:56 2025 +0800 feat(crm): 添加相关图片 commite4967760b7Merge:0c6766685102fcAuthor: 浅念 <email@sample.com> Date: Mon Jul 21 11:25:49 2025 +0800 Finish crm_pc commit85102fcf32Author: 浅念 <email@sample.com> Date: Mon Jul 21 11:24:06 2025 +0800 crm 接口对接 commit0c67666793Author: 浅念 <email@sample.com> Date: Wed Jul 16 17:18:14 2025 +0800 添加上传头部信息 commita41c75f703Author: 浅念 <email@sample.com> Date: Tue Jul 15 09:40:53 2025 +0800 修改页面 commit22ae0e86c8Author: 浅念 <email@sample.com> Date: Mon Jul 14 17:59:02 2025 +0800 修改页面 commit812e3c4b0cAuthor: 浅念 <email@sample.com> Date: Mon Jul 14 10:09:10 2025 +0800 修改菜单问题 commit2ad479b006Author: 浅念 <email@sample.com> Date: Fri Jul 11 19:45:57 2025 +0800 修改样式 commit5802e157bfAuthor: 浅念 <email@sample.com> Date: Fri Jul 11 19:43:34 2025 +0800 修改工单 commit713d43f7b4Author: 浅念 <email@sample.com> Date: Fri Jul 11 18:37:16 2025 +0800 添加登录 commit719911918fAuthor: 浅念 <email@sample.com> Date: Fri Jul 4 17:16:38 2025 +0800 项目创建 commitce47b39fa5Author: 浅念 <email@sample.com> Date: Wed Jul 2 09:37:51 2025 +0800 删除 # Conflicts: # src/App.vue # src/api/adminApi.ts # src/api/crmApi.ts # src/api/menuApi.ts # src/api/systemApi.ts # src/api/usersApi.ts # src/components/core/layouts/art-header-bar/index.vue # src/components/core/layouts/art-page-content/index.vue # src/router/routes/asyncRoutes.ts # src/router/routesAlias.ts # src/views/admin/customer/customeraudit.vue # src/views/admin/customer/highseas.vue # src/views/admin/customer/index.vue # src/views/admin/inquiry_system/index.vue # src/views/admin/system/company.vue # src/views/admin/system/feishu_app.vue # src/views/admin/system/menu/index.vue # src/views/admin/system/role/index.vue # src/views/admin/system/systems.vue # src/views/admin/user/index.vue # src/views/admin/user/user_info.vue # src/views/auth/login/index.vue # src/views/crmpc/customer/Add.vue # src/views/crmpc/customer/Edit.vue # src/views/crmpc/customer/Followadd.vue # src/views/crmpc/customer/Show.vue # src/views/crmpc/customer/index.vue # src/views/crmpc/highseas/index.vue # src/views/crmpc/recycle/index.vue # src/views/crmpc/team/team_customer.vue # src/views/crmpc/team/user_customer.vue # src/views/dashboard/console/index.vue # src/views/system/user-center/index.vue # src/views/work/myOrder/index.vue # src/views/work/order/index.vue
1374 lines
34 KiB
Vue
1374 lines
34 KiB
Vue
<template>
|
||
<div class="approval-flow-container">
|
||
<div class="main-content">
|
||
<!-- 左侧基本信息 -->
|
||
<div class="left-panel">
|
||
<h3 class="panel-title">基本信息</h3>
|
||
<el-form :model="form" label-width="80px">
|
||
<el-form-item label="名称">
|
||
<el-input v-model="form.name" placeholder="请输入流程名称" />
|
||
</el-form-item>
|
||
<el-form-item label="业务类型">
|
||
<el-input v-model="form.type" placeholder="请输入业务类型" />
|
||
</el-form-item>
|
||
<el-form-item label="超时时间">
|
||
<ElInput v-model="form.timeout_hours" placeholder="请输入超时时间">
|
||
<template #suffix>
|
||
<span>h</span>
|
||
</template>
|
||
</ElInput>
|
||
</el-form-item>
|
||
<el-form-item label="超时动作">
|
||
<el-select v-model="form.timeout_action" placeholder="请选择超时动作">
|
||
<el-option label="请选择" value="" />
|
||
<el-option label="全部同意" value="all_agree" />
|
||
<el-option label="全部拒绝" value="all_reject" />
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="是否启用">
|
||
<el-switch v-model="form.is_active" :active-value="1" :inactive-value="0" />
|
||
</el-form-item>
|
||
</el-form>
|
||
</div>
|
||
|
||
<!-- 中间审批流程 -->
|
||
<div class="middle-panel">
|
||
<h3 class="panel-title">审批流</h3>
|
||
<div class="flow-diagram">
|
||
<template v-for="(node, index) in form.nodes" :key="node.id">
|
||
<!-- 节点按钮 -->
|
||
<div class="node-container">
|
||
<el-button
|
||
type="primary"
|
||
icon="Plus"
|
||
@click="selectNode(node)"
|
||
class="node-btn"
|
||
:class="{
|
||
selected: selectedNodeId === node.id,
|
||
disabled: index === 0
|
||
}"
|
||
:disabled="index === 0"
|
||
>
|
||
</el-button>
|
||
<div class="node-info" @click="selectNode(node)">
|
||
<div class="node-title">{{ node.title }}</div>
|
||
<div class="node-subtitle">{{ node.subtitle }}</div>
|
||
</div>
|
||
<!-- 删除按钮 -->
|
||
<i
|
||
v-if="form.nodes.length >= 3 && index > 0"
|
||
class="iconfont-sys danger-color"
|
||
@click="removeNode(node.id)"
|
||
></i
|
||
>
|
||
</div>
|
||
|
||
<!-- 连接线 -->
|
||
<div v-if="index < form.nodes.length" class="connection-line">
|
||
<div class="dotted-line"></div>
|
||
<el-button
|
||
type="primary"
|
||
icon="Plus"
|
||
@click="addNodeAfter(node.id)"
|
||
class="add-connection-btn"
|
||
size="small"
|
||
circle
|
||
/>
|
||
</div>
|
||
</template>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 右侧审批人配置 -->
|
||
<div class="right-panel">
|
||
<div class="panel-header">
|
||
<h3 class="panel-title">审批人</h3>
|
||
</div>
|
||
|
||
<!-- 提示信息 -->
|
||
<div v-if="!selectedNode || selectedNodeId === form.nodes[0]?.id" class="no-selection">
|
||
<div class="no-selection-content">
|
||
<i class="el-icon-info"></i>
|
||
<p v-if="!selectedNode">请选择一个节点进行配置</p>
|
||
<p v-else>申请人节点为默认节点,不可配置</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div v-if="selectedNode && selectedNodeId !== form.nodes[0]?.id" class="approver-config">
|
||
<!-- 节点基本信息 -->
|
||
<div class="config-section">
|
||
<h4>节点信息</h4>
|
||
<el-form :model="selectedNode" label-width="60px" size="small">
|
||
<el-form-item label="名称">
|
||
<el-input
|
||
v-model="selectedNode.title"
|
||
placeholder="请输入节点名称"
|
||
@blur="updateNodeLabel"
|
||
/>
|
||
</el-form-item>
|
||
<el-form-item label="类型">
|
||
<el-select
|
||
v-model="selectedNode.type"
|
||
@change="onNodeTypeChange"
|
||
placeholder="请选择节点类型"
|
||
>
|
||
<el-option
|
||
v-for="item in approvalType"
|
||
:key="item.item_value"
|
||
:label="item.item_label"
|
||
:value="item.item_value"
|
||
/>
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="审批条件">
|
||
<el-input
|
||
v-model="selectedNode.condition"
|
||
placeholder="请输入审批条件)"
|
||
type="textarea"
|
||
:rows="2"
|
||
/>
|
||
</el-form-item>
|
||
<el-form-item label="是否必须">
|
||
<el-switch
|
||
v-model="selectedNode.required"
|
||
active-text="必须"
|
||
inactive-text="可选"
|
||
/>
|
||
</el-form-item>
|
||
</el-form>
|
||
</div>
|
||
|
||
<div class="config-section">
|
||
<h4>审批人</h4>
|
||
<el-checkbox-group v-model="selectedNode.approverUsers">
|
||
<!-- <el-checkbox label="上级领导">上级领导</el-checkbox> -->
|
||
</el-checkbox-group>
|
||
<div class="approver-groups">
|
||
<div
|
||
v-for="(group, groupIndex) in selectedNode.approverGroups"
|
||
:key="groupIndex"
|
||
class="approver-group"
|
||
>
|
||
<div class="group-header">
|
||
<span class="group-title">审批组 {{ groupIndex + 1 }}</span>
|
||
<el-button
|
||
v-if="selectedNode.approverGroups.length > 1"
|
||
type="danger"
|
||
size="small"
|
||
icon="Delete"
|
||
@click="removeApproverGroup(groupIndex)"
|
||
circle
|
||
/>
|
||
</div>
|
||
<div class="group-content">
|
||
<el-form-item label="类型" size="small">
|
||
<el-select
|
||
v-model="group.type"
|
||
placeholder="请选择审批类型"
|
||
@change="onGroupTypeChange(group)"
|
||
>
|
||
<el-option
|
||
v-for="item in approvalRole"
|
||
:key="item.item_value"
|
||
:label="item.item_label"
|
||
:value="item.item_value"
|
||
/>
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="选项" size="small">
|
||
<el-select
|
||
v-model="group.users"
|
||
multiple
|
||
placeholder="请选择"
|
||
:loading="group.loading"
|
||
ollapse-tags
|
||
filterable
|
||
:disabled="group.type === 'initiator_leader'"
|
||
>
|
||
<el-option
|
||
v-for="opt in group.options"
|
||
:key="opt.id"
|
||
:label="opt.name"
|
||
:value="opt.id"
|
||
/>
|
||
</el-select>
|
||
</el-form-item>
|
||
</div>
|
||
</div>
|
||
<el-button
|
||
type="primary"
|
||
size="small"
|
||
icon="Plus"
|
||
@click="addApproverGroup"
|
||
class="add-group-btn"
|
||
>
|
||
添加审批组
|
||
</el-button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="config-section">
|
||
<div class="cc-header">
|
||
<h4>是否抄送</h4>
|
||
<el-switch v-model="selectedNode.isCC" />
|
||
</div>
|
||
<div v-if="selectedNode.isCC" class="cc-config">
|
||
<h4>抄送人</h4>
|
||
<el-checkbox-group v-model="selectedNode.ccUsers">
|
||
<!-- <el-checkbox label="上级领导">上级领导</el-checkbox> -->
|
||
</el-checkbox-group>
|
||
<div class="cc-groups">
|
||
<div
|
||
v-for="(group, groupIndex) in selectedNode.ccGroups"
|
||
:key="groupIndex"
|
||
class="cc-group"
|
||
>
|
||
<div class="group-header">
|
||
<span class="group-title">抄送组 {{ groupIndex + 1 }}</span>
|
||
<el-button
|
||
v-if="selectedNode.ccGroups.length > 1"
|
||
type="danger"
|
||
size="small"
|
||
icon="Delete"
|
||
@click="removeCCGroup(groupIndex)"
|
||
>
|
||
</el-button>
|
||
</div>
|
||
<div class="group-content">
|
||
<el-form-item label="类型" size="small">
|
||
<el-select
|
||
v-model="group.type"
|
||
placeholder="请选择类型"
|
||
style="width: 100%"
|
||
@change="onGroupTypeChange(group)"
|
||
>
|
||
<el-option
|
||
v-for="item in approvalRole"
|
||
:key="item.item_value"
|
||
:label="item.item_label"
|
||
:value="item.item_value"
|
||
/>
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="选项" size="small">
|
||
<el-select
|
||
v-model="group.users"
|
||
multiple
|
||
placeholder="请选择"
|
||
:loading="group.loading"
|
||
:disabled="group.type === 'initiator_leader'"
|
||
>
|
||
<el-option
|
||
v-for="opt in group.options"
|
||
:key="opt.id"
|
||
:label="opt.name"
|
||
:value="opt.id"
|
||
/>
|
||
</el-select>
|
||
</el-form-item>
|
||
</div>
|
||
</div>
|
||
<el-button
|
||
type="primary"
|
||
size="small"
|
||
icon="Plus"
|
||
@click="addCCGroup"
|
||
class="add-group-btn"
|
||
>
|
||
添加抄送组
|
||
</el-button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- <div v-else class="no-selection">
|
||
<p>请选择一个节点进行配置</p>
|
||
</div> -->
|
||
</div>
|
||
</div>
|
||
<!-- 底部操作按钮 -->
|
||
<div class="bottom-actions">
|
||
<el-button @click="cancelFlow">取消</el-button>
|
||
<el-button type="primary" @click="saveFlow">保存</el-button>
|
||
</div>
|
||
<!-- 节点编辑弹框 -->
|
||
<el-dialog
|
||
v-model="editDialogVisible"
|
||
:title="editingNode.id === null ? '添加新节点' : '编辑节点名称'"
|
||
width="400px"
|
||
:close-on-click-modal="false"
|
||
>
|
||
<el-form :model="editingNode" label-width="80px">
|
||
<el-form-item label="节点名称">
|
||
<el-input v-model="editingNode.label" placeholder="请输入节点名称" />
|
||
</el-form-item>
|
||
</el-form>
|
||
|
||
<template #footer>
|
||
<el-button @click="cancelEdit">取消</el-button>
|
||
<el-button type="primary" @click="saveNode">确定</el-button>
|
||
</template>
|
||
</el-dialog>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { reactive, ref, onMounted } from 'vue'
|
||
import { useRoute, useRouter } from 'vue-router'
|
||
import { ElMessage } from 'element-plus'
|
||
import { commonService } from '@/api/commonApi'
|
||
import { manageService } from '@/api/adminApi'
|
||
defineOptions({ name: 'AdminApprovalEdit' })
|
||
//审批类型 AWF_STEP_TYPE
|
||
const approvalType = ref([])
|
||
//角色类型
|
||
const approvalRole = ref([])
|
||
const loadDictOptions = async () => {
|
||
const response = await commonService.getDictSelect({
|
||
scope: 'awf_step_type,awf_approvers_type',
|
||
scope_type: '1'
|
||
})
|
||
approvalType.value = response.awf_step_type
|
||
approvalRole.value = response.awf_approvers_type
|
||
}
|
||
|
||
const route = useRoute()
|
||
const router = useRouter()
|
||
|
||
onMounted(async () => {
|
||
await loadDictOptions()
|
||
await loadDetail()
|
||
})
|
||
|
||
// 审批流程数据
|
||
const form = reactive({
|
||
id: '',
|
||
name: '',
|
||
type: '',
|
||
timeout_hours: '',
|
||
timeout_action: '',
|
||
is_active: 1,
|
||
nodes: [
|
||
{
|
||
id: 1,
|
||
label: '申请人',
|
||
title: '申请人',
|
||
subtitle: '本人',
|
||
type: '',
|
||
condition: '',
|
||
required: true,
|
||
approverGroups: [
|
||
{
|
||
type: '',
|
||
users: [],
|
||
loading: false,
|
||
options: []
|
||
}
|
||
],
|
||
approvers: [],
|
||
businessApprovers: [],
|
||
approverUsers: [],
|
||
ccGroups: [
|
||
{
|
||
type: '',
|
||
users: [],
|
||
loading: false,
|
||
options: []
|
||
}
|
||
],
|
||
ccUsers: [],
|
||
isCC: false
|
||
},
|
||
{
|
||
id: 2,
|
||
label: '审批人',
|
||
title: '审批人',
|
||
subtitle: '上级',
|
||
type: '',
|
||
condition: '',
|
||
required: true,
|
||
approverGroups: [
|
||
{
|
||
type: '',
|
||
users: [],
|
||
loading: false,
|
||
options: []
|
||
}
|
||
],
|
||
approvers: [],
|
||
businessApprovers: [],
|
||
approverUsers: [],
|
||
ccGroups: [
|
||
{
|
||
type: '',
|
||
users: [],
|
||
loading: false,
|
||
options: []
|
||
}
|
||
],
|
||
ccUsers: [],
|
||
isCC: false
|
||
}
|
||
]
|
||
})
|
||
|
||
// 编辑弹框状态
|
||
const editDialogVisible = ref(false)
|
||
const editingNode = reactive({
|
||
id: null,
|
||
label: '',
|
||
afterNodeId: null // 用于记录在哪个节点后添加新节点
|
||
})
|
||
|
||
// 选中的节点
|
||
const selectedNodeId = ref(null)
|
||
const selectedNode = ref(null)
|
||
|
||
// 业务部用户数据(如需部门静态项,可在此填充)
|
||
// const businessUsers = ref([])
|
||
|
||
// 选项缓存,避免重复请求
|
||
const optionsCache = reactive({ role: [], user: [], department: [] })
|
||
|
||
// 懒加载并缓存不同类型的选项
|
||
const ensureOptionsLoaded = async (group) => {
|
||
const type = group.type
|
||
if (!type || type === 'initiator_leader') {
|
||
group.options = []
|
||
return
|
||
}
|
||
group.loading = true
|
||
try {
|
||
if (type === 'role') {
|
||
if (!optionsCache.role || optionsCache.role.length === 0) {
|
||
const response = await commonService.getRoleSelect()
|
||
optionsCache.role = response || []
|
||
}
|
||
console.log('optionsCache.role', optionsCache.role)
|
||
group.options = optionsCache.role
|
||
} else if (type === 'user') {
|
||
if (!optionsCache.user || optionsCache.user.length === 0) {
|
||
const response = await commonService.getUserSelect()
|
||
optionsCache.user = response || []
|
||
}
|
||
group.options = optionsCache.user
|
||
} else {
|
||
group.options = []
|
||
}
|
||
} finally {
|
||
group.loading = false
|
||
}
|
||
}
|
||
|
||
// 节点ID计数器
|
||
let nodeIdCounter = 3
|
||
|
||
// 选择节点
|
||
const selectNode = (node) => {
|
||
// 第一个节点(申请人)不可选择
|
||
const nodeIndex = form.nodes.findIndex((n) => n.id === node.id)
|
||
if (nodeIndex === 0) {
|
||
return
|
||
}
|
||
selectedNodeId.value = node.id
|
||
selectedNode.value = node
|
||
}
|
||
|
||
// 更新节点标签(当名称改变时)
|
||
const updateNodeLabel = () => {
|
||
if (selectedNode.value) {
|
||
selectedNode.value.label = selectedNode.value.title
|
||
}
|
||
}
|
||
|
||
// 节点类型改变
|
||
const onNodeTypeChange = (type) => {
|
||
if (selectedNode.value) {
|
||
// 根据类型设置默认值
|
||
if (type === 'applicant') {
|
||
selectedNode.value.subtitle = '本人'
|
||
} else if (type === 'approver') {
|
||
selectedNode.value.subtitle = '请选择'
|
||
} else if (type === 'cc') {
|
||
selectedNode.value.subtitle = '请选择'
|
||
selectedNode.value.isCC = true
|
||
}
|
||
}
|
||
}
|
||
|
||
// 添加审批组
|
||
const addApproverGroup = () => {
|
||
if (selectedNode.value) {
|
||
selectedNode.value.approverGroups.push({
|
||
type: '',
|
||
users: [],
|
||
loading: false,
|
||
options: optionsCache.department
|
||
})
|
||
}
|
||
}
|
||
|
||
// 删除审批组
|
||
const removeApproverGroup = (groupIndex) => {
|
||
if (selectedNode.value && selectedNode.value.approverGroups.length > 1) {
|
||
selectedNode.value.approverGroups.splice(groupIndex, 1)
|
||
}
|
||
}
|
||
|
||
// 添加抄送组
|
||
const addCCGroup = () => {
|
||
if (selectedNode.value) {
|
||
selectedNode.value.ccGroups.push({
|
||
type: '',
|
||
users: [],
|
||
loading: false,
|
||
options: optionsCache.department
|
||
})
|
||
}
|
||
}
|
||
|
||
// 删除抄送组
|
||
const removeCCGroup = (groupIndex) => {
|
||
if (selectedNode.value && selectedNode.value.ccGroups.length > 1) {
|
||
selectedNode.value.ccGroups.splice(groupIndex, 1)
|
||
}
|
||
}
|
||
|
||
// (已由 ensureOptionsLoaded 替代)
|
||
|
||
// 类型变化时,清空选项(如发起人上级则禁用)
|
||
const onGroupTypeChange = async (group) => {
|
||
group.users = []
|
||
group.options = []
|
||
await ensureOptionsLoaded(group)
|
||
}
|
||
|
||
// 加载详情并回显
|
||
const loadDetail = async () => {
|
||
const id = route.params.id || route.query.id
|
||
let data = {}
|
||
if (!id) return
|
||
await manageService.stockapprovaldetail({ id }).then((res) => {
|
||
data = res
|
||
})
|
||
|
||
console.log('data', data)
|
||
if (!data) return
|
||
form.id = data.id
|
||
form.name = data.name || ''
|
||
form.type = data.type || ''
|
||
form.timeout_hours = data.timeout_hours ?? ''
|
||
form.timeout_action = data.timeout_action || ''
|
||
form.is_active = data.is_active ? 1 : 0
|
||
data.steps = JSON.parse(data.steps)
|
||
console.log('data', data.steps)
|
||
// 重建节点:第一个默认申请人 + 每个步骤一个节点
|
||
const nodes = [form.nodes[0]]
|
||
if (Array.isArray(data.steps)) {
|
||
for (const step of data.steps) {
|
||
const node = {
|
||
id: ++nodeIdCounter,
|
||
label: step.name || '审批节点',
|
||
title: step.name || '审批节点',
|
||
subtitle: '上级',
|
||
type: step.type || 'any',
|
||
condition: step.condition || '',
|
||
required: !!step.required,
|
||
approverGroups: [],
|
||
approverUsers: [],
|
||
ccGroups: [],
|
||
ccUsers: [],
|
||
isCC: Array.isArray(step.cc) && step.cc.length > 0
|
||
}
|
||
|
||
// 审批组
|
||
if (Array.isArray(step.approvers)) {
|
||
for (const ap of step.approvers) {
|
||
const group = { type: ap.type || '', users: [], loading: false, options: [] }
|
||
await ensureOptionsLoaded(group)
|
||
if (ap.type === 'initiator_leader') {
|
||
group.users = []
|
||
} else if (ap.value) {
|
||
group.users = String(ap.value)
|
||
.split(',')
|
||
.map((v) => Number((v || '').trim()))
|
||
.filter((n) => !Number.isNaN(n))
|
||
}
|
||
node.approverGroups.push(group)
|
||
}
|
||
} else {
|
||
// 至少保留一个空组方便编辑
|
||
const group = { type: '', users: [], loading: false, options: [] }
|
||
await ensureOptionsLoaded(group)
|
||
node.approverGroups.push(group)
|
||
}
|
||
|
||
// 抄送组
|
||
if (Array.isArray(step.cc)) {
|
||
for (const c of step.cc) {
|
||
const group = { type: c.type || '', users: [], loading: false, options: [] }
|
||
await ensureOptionsLoaded(group)
|
||
if (c.type === 'initiator_leader') {
|
||
group.users = []
|
||
} else if (c.value) {
|
||
group.users = String(c.value)
|
||
.split(',')
|
||
.map((v) => Number((v || '').trim()))
|
||
.filter((n) => !Number.isNaN(n))
|
||
}
|
||
node.ccGroups.push(group)
|
||
}
|
||
} else {
|
||
const group = { type: '', users: [], loading: false, options: [] }
|
||
await ensureOptionsLoaded(group)
|
||
node.ccGroups.push(group)
|
||
}
|
||
|
||
nodes.push(node)
|
||
}
|
||
}
|
||
|
||
form.nodes = nodes
|
||
}
|
||
|
||
// 保存节点
|
||
const saveNode = () => {
|
||
if (editingNode.id === null) {
|
||
// 添加新节点
|
||
if (editingNode.afterNodeId) {
|
||
const afterIndex = form.nodes.findIndex((n) => n.id === editingNode.afterNodeId)
|
||
if (afterIndex !== -1) {
|
||
const newNode = {
|
||
id: ++nodeIdCounter,
|
||
label: editingNode.label,
|
||
title: editingNode.label,
|
||
subtitle: '请选择',
|
||
type: '',
|
||
condition: '',
|
||
required: true,
|
||
approverGroups: [
|
||
{
|
||
type: '',
|
||
users: [],
|
||
loading: false
|
||
}
|
||
],
|
||
approvers: [],
|
||
businessApprovers: [],
|
||
ccUsers: [],
|
||
businessCCUsers: [],
|
||
isCC: false
|
||
}
|
||
form.nodes.splice(afterIndex + 1, 0, newNode)
|
||
}
|
||
}
|
||
} else {
|
||
// 编辑现有节点
|
||
const nodeIndex = form.nodes.findIndex((n) => n.id === editingNode.id)
|
||
if (nodeIndex !== -1) {
|
||
form.nodes[nodeIndex].label = editingNode.label
|
||
form.nodes[nodeIndex].title = editingNode.label
|
||
}
|
||
}
|
||
// 重置编辑状态
|
||
editingNode.id = null
|
||
editingNode.label = ''
|
||
editingNode.afterNodeId = null
|
||
editDialogVisible.value = false
|
||
}
|
||
|
||
// 在指定节点后添加新节点
|
||
const addNodeAfter = (afterNodeId) => {
|
||
// 先打开编辑弹框,让用户输入节点名称
|
||
editingNode.id = null // 设置为null表示这是新节点
|
||
editingNode.label = ''
|
||
editingNode.afterNodeId = afterNodeId
|
||
editDialogVisible.value = true
|
||
}
|
||
|
||
// 取消编辑
|
||
const cancelEdit = () => {
|
||
// 重置编辑状态
|
||
editingNode.id = null
|
||
editingNode.label = ''
|
||
editingNode.afterNodeId = null
|
||
editDialogVisible.value = false
|
||
}
|
||
|
||
// 删除节点
|
||
const removeNode = (nodeId) => {
|
||
const nodeIndex = form.nodes.findIndex((n) => n.id === nodeId)
|
||
if (nodeIndex !== -1 && nodeIndex > 0) {
|
||
form.nodes.splice(nodeIndex, 1)
|
||
}
|
||
}
|
||
|
||
// 保存流程 -> 组装为后端需要的结构
|
||
const saveFlow = async () => {
|
||
const timeout = Number(form.timeout_hours || 0)
|
||
if (timeout > 0 && !form.timeout_action) {
|
||
ElMessage.error('当超时时间大于0时,必须选择超时动作')
|
||
return
|
||
}
|
||
const payload = {
|
||
id: form.id,
|
||
name: form.name,
|
||
type: form.type,
|
||
timeout_hours: timeout,
|
||
timeout_action: form.timeout_action,
|
||
is_active: !!form.is_active,
|
||
steps: []
|
||
}
|
||
|
||
const steps = []
|
||
form.nodes.forEach((node, idx) => {
|
||
// 跳过第一个默认的申请人节点
|
||
if (idx === 0) return
|
||
|
||
const approvers = []
|
||
// 组审批
|
||
if (Array.isArray(node.approverGroups)) {
|
||
node.approverGroups.forEach((group) => {
|
||
if (group && group.type === 'initiator_leader') {
|
||
approvers.push({ type: 'initiator_leader' })
|
||
} else if (group && group.type && Array.isArray(group.users) && group.users.length > 0) {
|
||
approvers.push({ type: group.type, value: group.users.join(',') })
|
||
}
|
||
})
|
||
}
|
||
// // 单选“上级领导”
|
||
// if (Array.isArray(node.approverUsers) && node.approverUsers.includes('上级领导')) {
|
||
// approvers.push({ type: 'initiator_leader' })
|
||
// }
|
||
|
||
const cc = []
|
||
if (node.isCC && Array.isArray(node.ccGroups)) {
|
||
node.ccGroups.forEach((group) => {
|
||
if (group && group.type === 'initiator_leader') {
|
||
cc.push({ type: 'initiator_leader' })
|
||
} else if (group && group.type && Array.isArray(group.users) && group.users.length > 0) {
|
||
cc.push({ type: group.type, value: group.users.join(',') })
|
||
}
|
||
})
|
||
}
|
||
// if (node.isCC && Array.isArray(node.ccUsers) && node.ccUsers.includes('上级领导')) {
|
||
// cc.push({ type: 'initiator_leader' })
|
||
// }
|
||
|
||
steps.push({
|
||
name: node.title || node.label || '',
|
||
type: node.type || 'any',
|
||
approvers,
|
||
cc,
|
||
condition: node.condition || '',
|
||
required: !!node.required
|
||
})
|
||
})
|
||
payload.steps = steps
|
||
const { message } = await manageService.stockapprovalupdate(payload)
|
||
ElMessage.success(message)
|
||
console.log('保存的流程数据:', payload)
|
||
setTimeout(() => {
|
||
router.back()
|
||
}, 300)
|
||
}
|
||
|
||
// 取消流程
|
||
const cancelFlow = () => {
|
||
console.log('取消流程编辑')
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
.approval-flow-container {
|
||
display: flex;
|
||
flex-direction: column;
|
||
height: 88vh;
|
||
/* padding: 20px; */
|
||
/* gap: 20px; */
|
||
}
|
||
|
||
.main-content {
|
||
display: flex;
|
||
flex: 1;
|
||
gap: 20px;
|
||
}
|
||
|
||
.left-panel,
|
||
.middle-panel,
|
||
.right-panel {
|
||
background: #fff;
|
||
border-radius: 8px;
|
||
padding: 20px;
|
||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||
height: 75vh;
|
||
}
|
||
|
||
.left-panel {
|
||
width: 300px;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.middle-panel {
|
||
flex: 1;
|
||
min-width: 400px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.right-panel {
|
||
width: 350px;
|
||
flex-shrink: 0;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.panel-title {
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
color: #303133;
|
||
margin-bottom: 20px;
|
||
padding-bottom: 10px;
|
||
border-bottom: 1px solid #ebeef5;
|
||
}
|
||
|
||
.panel-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.panel-header .panel-title {
|
||
margin-bottom: 0;
|
||
border-bottom: none;
|
||
}
|
||
|
||
.unit {
|
||
margin-left: 8px;
|
||
color: #909399;
|
||
}
|
||
|
||
.flow-diagram {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: flex-start;
|
||
gap: 0;
|
||
flex: 1;
|
||
overflow-y: auto;
|
||
padding: 20px 10px;
|
||
max-height: calc(100vh - 200px);
|
||
}
|
||
|
||
.node-container {
|
||
display: flex;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
gap: 15px;
|
||
position: relative;
|
||
margin: 10px 0;
|
||
}
|
||
|
||
.node-btn {
|
||
width: 50px;
|
||
height: 50px !important;
|
||
border-radius: 8px;
|
||
font-size: 16px;
|
||
font-weight: bold;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
box-shadow: 0 2px 8px rgba(64, 158, 255, 0.3);
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.node-btn:hover {
|
||
transform: translateY(-2px);
|
||
box-shadow: 0 4px 12px rgba(64, 158, 255, 0.4);
|
||
}
|
||
|
||
.node-btn.selected {
|
||
background-color: #67c23a;
|
||
border-color: #67c23a;
|
||
}
|
||
|
||
.node-btn.selected:hover {
|
||
background-color: #85ce61;
|
||
border-color: #85ce61;
|
||
}
|
||
|
||
.node-btn.disabled {
|
||
opacity: 0.6;
|
||
cursor: not-allowed;
|
||
background-color: #6ca3f5;
|
||
border-color: #6ca3f5;
|
||
color: #fff;
|
||
box-shadow: none;
|
||
}
|
||
|
||
.node-btn.disabled:hover {
|
||
background-color: #f5f7fa;
|
||
border-color: #dcdfe6;
|
||
color: #909399;
|
||
transform: none;
|
||
box-shadow: none;
|
||
}
|
||
|
||
.cc-node {
|
||
background-color: #67c23a;
|
||
border-color: #67c23a;
|
||
}
|
||
|
||
.cc-node:hover {
|
||
background-color: #85ce61;
|
||
border-color: #85ce61;
|
||
}
|
||
|
||
.node-info {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 4px;
|
||
/* min-width: 120px; */
|
||
text-align: left;
|
||
}
|
||
|
||
.node-title {
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
color: #303133;
|
||
line-height: 1.2;
|
||
}
|
||
|
||
.node-subtitle {
|
||
font-size: 14px;
|
||
color: #909399;
|
||
line-height: 1.2;
|
||
}
|
||
|
||
.danger-color {
|
||
position: absolute;
|
||
right: -30px;
|
||
top: 50%;
|
||
transform: translateY(-50%);
|
||
color: #f56c6c;
|
||
}
|
||
|
||
.connection-line {
|
||
position: relative;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
margin: 5px 0;
|
||
}
|
||
|
||
.dotted-line {
|
||
width: 2px;
|
||
height: 80px;
|
||
background: repeating-linear-gradient(
|
||
to bottom,
|
||
#409eff 0px,
|
||
#409eff 4px,
|
||
transparent 4px,
|
||
transparent 8px
|
||
);
|
||
margin: 10px 0;
|
||
}
|
||
|
||
.add-connection-btn {
|
||
width: 24px;
|
||
height: 24px;
|
||
padding: 0;
|
||
background-color: #409eff;
|
||
border-color: #409eff;
|
||
position: absolute;
|
||
top: 50%;
|
||
left: 50%;
|
||
transform: translate(-50%, -50%);
|
||
z-index: 1;
|
||
}
|
||
|
||
.add-connection-btn:hover {
|
||
background-color: #66b1ff;
|
||
border-color: #66b1ff;
|
||
}
|
||
|
||
.approver-config {
|
||
margin-top: 20px;
|
||
flex: 1;
|
||
overflow-y: auto;
|
||
padding-right: 10px;
|
||
}
|
||
|
||
/* 滚动条样式 */
|
||
.flow-diagram::-webkit-scrollbar,
|
||
.approver-config::-webkit-scrollbar {
|
||
width: 6px;
|
||
}
|
||
|
||
.flow-diagram::-webkit-scrollbar-track,
|
||
.approver-config::-webkit-scrollbar-track {
|
||
background: #f1f1f1;
|
||
border-radius: 3px;
|
||
}
|
||
|
||
.flow-diagram::-webkit-scrollbar-thumb,
|
||
.approver-config::-webkit-scrollbar-thumb {
|
||
background: #c1c1c1;
|
||
border-radius: 3px;
|
||
}
|
||
|
||
.flow-diagram::-webkit-scrollbar-thumb:hover,
|
||
.approver-config::-webkit-scrollbar-thumb:hover {
|
||
background: #a8a8a8;
|
||
}
|
||
|
||
/* 确保滚动区域有足够的最小高度 */
|
||
.flow-diagram {
|
||
min-height: 300px;
|
||
}
|
||
|
||
.config-section {
|
||
margin-bottom: 30px;
|
||
}
|
||
|
||
.config-section h4 {
|
||
font-size: 14px;
|
||
font-weight: 600;
|
||
color: #303133;
|
||
margin-bottom: 15px;
|
||
}
|
||
|
||
.config-section:first-child {
|
||
margin-bottom: 20px;
|
||
padding-bottom: 15px;
|
||
border-bottom: 1px solid #ebeef5;
|
||
}
|
||
|
||
.no-selection {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
height: 200px;
|
||
}
|
||
|
||
.no-selection-content {
|
||
text-align: center;
|
||
color: #909399;
|
||
}
|
||
|
||
.no-selection-content i {
|
||
font-size: 48px;
|
||
margin-bottom: 16px;
|
||
display: block;
|
||
}
|
||
|
||
.no-selection-content p {
|
||
margin: 0;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.approver-list {
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.config-section .el-checkbox-group {
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.approver-groups {
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.approver-group {
|
||
border: 1px solid #ebeef5;
|
||
border-radius: 6px;
|
||
margin-bottom: 16px;
|
||
padding: 16px;
|
||
background: #fafafa;
|
||
}
|
||
|
||
.group-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.group-title {
|
||
font-weight: 600;
|
||
color: #303133;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.group-content {
|
||
display: flex;
|
||
gap: 16px;
|
||
align-items: flex-end;
|
||
}
|
||
|
||
.group-content .el-form-item {
|
||
flex: 1;
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.add-group-btn {
|
||
width: 100%;
|
||
margin-top: 8px;
|
||
}
|
||
|
||
.cc-config .el-checkbox-group {
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.cc-groups {
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.cc-group {
|
||
border: 1px solid #ebeef5;
|
||
border-radius: 6px;
|
||
margin-bottom: 16px;
|
||
padding: 16px;
|
||
background: #fafafa;
|
||
}
|
||
|
||
.department-group {
|
||
margin-top: 10px;
|
||
}
|
||
|
||
.cc-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 15px;
|
||
}
|
||
|
||
.cc-header h4 {
|
||
margin: 0;
|
||
font-weight: 600;
|
||
color: #303133;
|
||
}
|
||
|
||
.cc-config {
|
||
margin-top: 15px;
|
||
}
|
||
|
||
.no-selection {
|
||
text-align: center;
|
||
color: #909399;
|
||
margin-top: 50px;
|
||
}
|
||
|
||
.no-selection p {
|
||
margin: 0;
|
||
}
|
||
|
||
.bottom-actions {
|
||
display: flex;
|
||
justify-content: center;
|
||
gap: 20px;
|
||
padding: 20px 0;
|
||
}
|
||
|
||
/* 弹框样式优化 */
|
||
:deep(.el-dialog__body) {
|
||
padding: 20px;
|
||
}
|
||
|
||
:deep(.el-form-item) {
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
:deep(.el-form-item__label) {
|
||
font-weight: 600;
|
||
color: #303133;
|
||
}
|
||
|
||
:deep(.el-input__inner) {
|
||
border-radius: 6px;
|
||
}
|
||
|
||
:deep(.el-select) {
|
||
width: 100%;
|
||
}
|
||
|
||
:deep(.el-select .el-input__inner) {
|
||
border-radius: 6px;
|
||
}
|
||
|
||
/* 移动端适配 */
|
||
@media (max-width: 768px) {
|
||
.approval-flow-container {
|
||
height: auto;
|
||
min-height: 100vh;
|
||
padding: 10px;
|
||
}
|
||
|
||
.main-content {
|
||
flex-direction: column;
|
||
gap: 15px;
|
||
}
|
||
|
||
.left-panel,
|
||
.middle-panel,
|
||
.right-panel {
|
||
width: 100%;
|
||
height: auto;
|
||
min-height: auto;
|
||
padding: 15px;
|
||
margin-bottom: 15px;
|
||
}
|
||
|
||
.left-panel {
|
||
order: 1;
|
||
}
|
||
|
||
.middle-panel {
|
||
order: 2;
|
||
min-width: auto;
|
||
}
|
||
|
||
.right-panel {
|
||
order: 3;
|
||
}
|
||
|
||
.flow-diagram {
|
||
max-height: 400px;
|
||
padding: 15px 5px;
|
||
}
|
||
|
||
.node-container {
|
||
flex-direction: column;
|
||
gap: 10px;
|
||
margin: 15px 0;
|
||
}
|
||
|
||
.node-btn {
|
||
width: 60px;
|
||
height: 60px;
|
||
font-size: 18px;
|
||
}
|
||
|
||
.node-info {
|
||
min-width: auto;
|
||
text-align: center;
|
||
}
|
||
|
||
.node-title {
|
||
font-size: 14px;
|
||
}
|
||
|
||
.node-subtitle {
|
||
font-size: 12px;
|
||
}
|
||
|
||
.connection-line {
|
||
margin: 0px 0;
|
||
}
|
||
|
||
.dotted-line {
|
||
height: 75px;
|
||
}
|
||
|
||
.add-node-btn {
|
||
width: 40px;
|
||
height: 40px;
|
||
font-size: 16px;
|
||
}
|
||
|
||
.approver-config {
|
||
max-height: 300px;
|
||
}
|
||
|
||
.approver-group,
|
||
.cc-group {
|
||
padding: 12px;
|
||
}
|
||
|
||
.group-content {
|
||
flex-direction: column;
|
||
gap: 12px;
|
||
}
|
||
|
||
.group-content .el-form-item {
|
||
flex: none;
|
||
}
|
||
|
||
.bottom-actions {
|
||
flex-direction: column;
|
||
gap: 15px;
|
||
padding: 15px 0;
|
||
}
|
||
|
||
.bottom-actions .el-button {
|
||
width: 100%;
|
||
}
|
||
|
||
.cc-header {
|
||
flex-direction: column;
|
||
align-items: flex-start;
|
||
gap: 10px;
|
||
}
|
||
|
||
.cc-header h4 {
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.panel-title {
|
||
font-size: 14px;
|
||
margin-bottom: 15px;
|
||
}
|
||
|
||
.form-row {
|
||
flex-direction: column;
|
||
gap: 15px;
|
||
}
|
||
|
||
.form-row .el-form-item {
|
||
flex: none;
|
||
}
|
||
}
|
||
|
||
/* 超小屏幕适配 */
|
||
@media (max-width: 480px) {
|
||
.approval-flow-container {
|
||
padding: 5px;
|
||
}
|
||
|
||
.left-panel,
|
||
.middle-panel,
|
||
.right-panel {
|
||
padding: 10px;
|
||
}
|
||
|
||
.node-btn {
|
||
width: 50px;
|
||
height: 50px;
|
||
font-size: 16px;
|
||
}
|
||
|
||
.node-title {
|
||
font-size: 13px;
|
||
}
|
||
|
||
.node-subtitle {
|
||
font-size: 11px;
|
||
}
|
||
|
||
.flow-diagram {
|
||
padding: 10px 5px;
|
||
}
|
||
|
||
.approver-config {
|
||
max-height: 250px;
|
||
}
|
||
|
||
.approver-group,
|
||
.cc-group {
|
||
padding: 10px;
|
||
}
|
||
}
|
||
</style>
|