|
|
@ -9,21 +9,10 @@ |
|
|
</el-button> |
|
|
</el-button> |
|
|
</div> |
|
|
</div> |
|
|
<div class="flex items-center"> |
|
|
<div class="flex items-center"> |
|
|
<el-input |
|
|
<el-input v-model="state.searchParams.config_name" class="w-200px mr-15px" placeholder="请输入配置名称" |
|
|
v-model="state.searchParams.config_name" |
|
|
clearable @keyup.enter="handleSearch" @clear="handleSearch" /> |
|
|
class="w-200px mr-15px" |
|
|
<el-select v-model="state.searchParams.status" class="w-150px mr-15px" placeholder="请选择状态" clearable |
|
|
placeholder="请输入配置名称" |
|
|
@change="handleSearch"> |
|
|
clearable |
|
|
|
|
|
@keyup.enter="handleSearch" |
|
|
|
|
|
@clear="handleSearch" |
|
|
|
|
|
/> |
|
|
|
|
|
<el-select |
|
|
|
|
|
v-model="state.searchParams.status" |
|
|
|
|
|
class="w-150px mr-15px" |
|
|
|
|
|
placeholder="请选择状态" |
|
|
|
|
|
clearable |
|
|
|
|
|
@change="handleSearch" |
|
|
|
|
|
> |
|
|
|
|
|
<el-option label="启用" :value="1" /> |
|
|
<el-option label="启用" :value="1" /> |
|
|
<el-option label="禁用" :value="0" /> |
|
|
<el-option label="禁用" :value="0" /> |
|
|
</el-select> |
|
|
</el-select> |
|
|
@ -38,23 +27,15 @@ |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<el-table |
|
|
<el-table v-loading="state.loading" class="mt-15px" :data="state.configList" |
|
|
v-loading="state.loading" |
|
|
:header-cell-style="{ background: '#fafafa', color: '#606266' }"> |
|
|
class="mt-15px" |
|
|
|
|
|
:data="state.configList" |
|
|
|
|
|
:header-cell-style="{ background: '#fafafa', color: '#606266' }" |
|
|
|
|
|
> |
|
|
|
|
|
<el-table-column label="ID" prop="id" width="80" /> |
|
|
<el-table-column label="ID" prop="id" width="80" /> |
|
|
<el-table-column label="配置名称" prop="config_name" min-width="180" /> |
|
|
<el-table-column label="配置名称" prop="config_name" min-width="180" /> |
|
|
<el-table-column label="配置描述" prop="description" min-width="200" show-overflow-tooltip /> |
|
|
<el-table-column label="配置描述" prop="description" min-width="200" show-overflow-tooltip /> |
|
|
<el-table-column label="状态" prop="status" width="100"> |
|
|
<el-table-column label="状态" prop="status" width="100"> |
|
|
<template #default="{ row }"> |
|
|
<template #default="{ row }"> |
|
|
<el-switch |
|
|
<el-switch v-model="row.status" :active-value="1" :inactive-value="0" |
|
|
v-model="row.status" |
|
|
@change="handleStatusChange(row)" /> |
|
|
:active-value="1" |
|
|
|
|
|
:inactive-value="0" |
|
|
|
|
|
@change="handleStatusChange(row)" |
|
|
|
|
|
/> |
|
|
|
|
|
</template> |
|
|
</template> |
|
|
</el-table-column> |
|
|
</el-table-column> |
|
|
<el-table-column label="创建时间" prop="created_at" width="180" /> |
|
|
<el-table-column label="创建时间" prop="created_at" width="180" /> |
|
|
@ -74,132 +55,100 @@ |
|
|
</el-table> |
|
|
</el-table> |
|
|
|
|
|
|
|
|
<div class="flex justify-end mt-15px"> |
|
|
<div class="flex justify-end mt-15px"> |
|
|
<el-pagination |
|
|
<el-pagination v-model:current-page="state.searchParams.page" |
|
|
v-model:current-page="state.searchParams.page" |
|
|
v-model:page-size="state.searchParams.limit" :page-sizes="[10, 20, 50, 100]" :total="state.total" |
|
|
v-model:page-size="state.searchParams.limit" |
|
|
layout="total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange" |
|
|
:page-sizes="[10, 20, 50, 100]" |
|
|
@current-change="handleCurrentChange" /> |
|
|
:total="state.total" |
|
|
|
|
|
layout="total, sizes, prev, pager, next, jumper" |
|
|
|
|
|
@size-change="handleSizeChange" |
|
|
|
|
|
@current-change="handleCurrentChange" |
|
|
|
|
|
/> |
|
|
|
|
|
</div> |
|
|
</div> |
|
|
</el-card> |
|
|
</el-card> |
|
|
|
|
|
|
|
|
<!-- 新增/编辑弹窗 --> |
|
|
<!-- 新增/编辑弹窗 --> |
|
|
<el-dialog |
|
|
<el-dialog v-model="state.dialog.visible" :title="state.dialog.title" width="800px" |
|
|
v-model="state.dialog.visible" |
|
|
:close-on-click-modal="false" :destroy-on-close="true"> |
|
|
:title="state.dialog.title" |
|
|
<el-form ref="formRef" :model="state.dialog.form" :rules="state.dialog.rules" label-width="120px"> |
|
|
width="800px" |
|
|
|
|
|
:close-on-click-modal="false" |
|
|
|
|
|
:destroy-on-close="true" |
|
|
|
|
|
> |
|
|
|
|
|
<el-form |
|
|
|
|
|
ref="formRef" |
|
|
|
|
|
:model="state.dialog.form" |
|
|
|
|
|
:rules="state.dialog.rules" |
|
|
|
|
|
label-width="120px" |
|
|
|
|
|
> |
|
|
|
|
|
<el-form-item label="配置名称" prop="config_name"> |
|
|
<el-form-item label="配置名称" prop="config_name"> |
|
|
<el-input v-model="state.dialog.form.config_name" placeholder="请输入配置名称" /> |
|
|
<el-input v-model="state.dialog.form.config_name" placeholder="请输入配置名称" /> |
|
|
</el-form-item> |
|
|
</el-form-item> |
|
|
<el-form-item label="配置描述" prop="description"> |
|
|
<el-form-item label="配置描述" prop="description"> |
|
|
<el-input |
|
|
<el-input v-model="state.dialog.form.description" type="textarea" :rows="3" placeholder="请输入配置描述" /> |
|
|
v-model="state.dialog.form.description" |
|
|
|
|
|
type="textarea" |
|
|
|
|
|
:rows="3" |
|
|
|
|
|
placeholder="请输入配置描述" |
|
|
|
|
|
/> |
|
|
|
|
|
</el-form-item> |
|
|
</el-form-item> |
|
|
<el-form-item label="状态" prop="status"> |
|
|
<el-form-item label="状态" prop="status"> |
|
|
<el-switch |
|
|
<el-switch v-model="state.dialog.form.status" :active-value="1" :inactive-value="0" /> |
|
|
v-model="state.dialog.form.status" |
|
|
|
|
|
:active-value="1" |
|
|
|
|
|
:inactive-value="0" |
|
|
|
|
|
/> |
|
|
|
|
|
</el-form-item> |
|
|
</el-form-item> |
|
|
<el-form-item label="审批节点" prop="nodes"> |
|
|
<el-form-item label="审批节点" prop="nodes"> |
|
|
<div class="mb-10px"> |
|
|
<!-- 添加节点按钮 --> |
|
|
<el-button type="primary" @click="handleAddNode"> |
|
|
<div class="mb-4"> |
|
|
<icon name="add" class="mr-5px" /> |
|
|
<el-button type="primary" @click="handleAddNode" size="small"> |
|
|
|
|
|
<icon name="add" class="mr-1" /> |
|
|
添加节点 |
|
|
添加节点 |
|
|
</el-button> |
|
|
</el-button> |
|
|
</div> |
|
|
</div> |
|
|
<div v-if="state.dialog.form.nodes.length === 0" class="text-gray-400 text-center py-20px border border-dashed rounded"> |
|
|
|
|
|
|
|
|
<!-- 无节点提示 --> |
|
|
|
|
|
<div v-if="state.dialog.form.nodes.length === 0" |
|
|
|
|
|
class="text-gray-400 text-center py-6 border border-dashed rounded bg-gray-50"> |
|
|
暂无审批节点,请点击添加 |
|
|
暂无审批节点,请点击添加 |
|
|
</div> |
|
|
</div> |
|
|
<div v-else class="node-list"> |
|
|
|
|
|
<div |
|
|
<!-- 节点列表 --> |
|
|
v-for="(element, index) in state.dialog.form.nodes" |
|
|
<div v-else class="space-y-4"> |
|
|
:key="index" |
|
|
<div v-for="(element, index) in state.dialog.form.nodes" :key="index" |
|
|
class="node-item p-15px mb-15px border border-gray-200 rounded" |
|
|
class="p-4 border border-gray-300 rounded-md bg-white shadow-sm"> |
|
|
> |
|
|
<!-- 节点头部 --> |
|
|
<div class="flex justify-between items-center mb-10px"> |
|
|
<div class="flex justify-between items-center mb-4"> |
|
|
<div class="flex items-center"> |
|
|
<div class="flex items-center text-gray-800 font-medium"> |
|
|
<icon name="rank" class="drag-handle mr-5px cursor-move" /> |
|
|
<icon name="rank" class="drag-handle mr-2 text-gray-500 cursor-move" /> |
|
|
<span class="font-bold">节点 {{ index + 1 }}</span> |
|
|
节点 {{ index + 1 }} |
|
|
</div> |
|
|
</div> |
|
|
<el-button type="danger" link @click="handleRemoveNode(index)"> |
|
|
<el-button type="danger" link @click="handleRemoveNode(index)"> |
|
|
删除 |
|
|
删除 |
|
|
</el-button> |
|
|
</el-button> |
|
|
</div> |
|
|
</div> |
|
|
<div class="flex items-center mb-10px"> |
|
|
|
|
|
<span class="w-100px">节点名称:</span> |
|
|
<!-- 节点名称 --> |
|
|
<el-input |
|
|
<div class="flex items-center mb-3"> |
|
|
v-model="element.node_name" |
|
|
<span class="w-28 text-gray-600">节点名称:</span> |
|
|
placeholder="请输入节点名称" |
|
|
<el-input v-model="element.node_name" placeholder="请输入节点名称" size="small" style="width: 73%;"/> |
|
|
/> |
|
|
|
|
|
</div> |
|
|
</div> |
|
|
<div class="flex items-center mb-10px"> |
|
|
|
|
|
<span class="w-100px">审批人类型:</span> |
|
|
<!-- 审批人类型 --> |
|
|
<el-select |
|
|
<div class="flex items-center mb-3"> |
|
|
v-model="element.approver_type" |
|
|
<span class="w-28 text-gray-600">审批人类型:</span> |
|
|
class="flex-1" |
|
|
<el-select v-model="element.approver_type" class="flex-1" placeholder="请选择审批人类型" |
|
|
placeholder="请选择审批人类型" |
|
|
size="small"> |
|
|
> |
|
|
|
|
|
<el-option label="指定用户" value="user" /> |
|
|
<el-option label="指定用户" value="user" /> |
|
|
<el-option label="指定角色" value="role" /> |
|
|
<el-option label="指定角色" value="role" /> |
|
|
<el-option label="指定部门" value="department" /> |
|
|
<el-option label="指定部门" value="department" /> |
|
|
</el-select> |
|
|
</el-select> |
|
|
</div> |
|
|
</div> |
|
|
<div class="flex items-center mb-10px"> |
|
|
|
|
|
<span class="w-100px">审批人:</span> |
|
|
<!-- 审批 --> |
|
|
<el-select |
|
|
<div class="flex items-center mb-3"> |
|
|
v-model="element.approver_ids" |
|
|
<span class="w-28 text-gray-600">审批:</span> |
|
|
class="flex-1" |
|
|
<el-select v-model="element.approver_ids" class="flex-1" multiple placeholder="请选择审批" |
|
|
multiple |
|
|
size="small"> |
|
|
placeholder="请选择审批人" |
|
|
<!-- 用户 --> |
|
|
> |
|
|
|
|
|
<!-- 这里根据 approver_type 不同显示不同的选项 --> |
|
|
|
|
|
<template v-if="element.approver_type === 'user'"> |
|
|
<template v-if="element.approver_type === 'user'"> |
|
|
<el-option |
|
|
<el-option v-for="item in state.userOptions" :key="item.id" :label="item.name" |
|
|
v-for="item in state.userOptions" |
|
|
:value="String(item.id)" /> |
|
|
:key="item.value" |
|
|
|
|
|
:label="item.label" |
|
|
|
|
|
:value="item.value" |
|
|
|
|
|
/> |
|
|
|
|
|
</template> |
|
|
</template> |
|
|
|
|
|
<!-- 角色 --> |
|
|
<template v-else-if="element.approver_type === 'role'"> |
|
|
<template v-else-if="element.approver_type === 'role'"> |
|
|
<el-option |
|
|
<el-option v-for="item in state.roleOptions" :key="item.role_id" |
|
|
v-for="item in state.roleOptions" |
|
|
:label="item.role_name" :value="String(item.role_id)" /> |
|
|
:key="item.value" |
|
|
|
|
|
:label="item.label" |
|
|
|
|
|
:value="item.value" |
|
|
|
|
|
/> |
|
|
|
|
|
</template> |
|
|
</template> |
|
|
|
|
|
<!-- 部门 --> |
|
|
<template v-else-if="element.approver_type === 'department'"> |
|
|
<template v-else-if="element.approver_type === 'department'"> |
|
|
<el-option |
|
|
<el-option v-for="item in state.departmentOptions" :key="item.id" |
|
|
v-for="item in state.departmentOptions" |
|
|
:label="item.department_name" :value="String(item.id)" /> |
|
|
:key="item.value" |
|
|
|
|
|
:label="item.label" |
|
|
|
|
|
:value="item.value" |
|
|
|
|
|
/> |
|
|
|
|
|
</template> |
|
|
</template> |
|
|
</el-select> |
|
|
</el-select> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
<!-- 审批类型 --> |
|
|
<div class="flex items-center"> |
|
|
<div class="flex items-center"> |
|
|
<span class="w-100px">审批类型:</span> |
|
|
<span class="w-28 text-gray-600">审批类型:</span> |
|
|
<el-radio-group v-model="element.sign_type"> |
|
|
<el-radio-group v-model="element.sign_type" size="small"> |
|
|
<el-radio label="or_sign">或签(一人通过即可)</el-radio> |
|
|
<el-radio label="or_sign">或签(一人通过即可)</el-radio> |
|
|
<el-radio label="and_sign">会签(需全部通过)</el-radio> |
|
|
<el-radio label="and_sign">会签(需全部通过)</el-radio> |
|
|
</el-radio-group> |
|
|
</el-radio-group> |
|
|
@ -207,6 +156,7 @@ |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</el-form-item> |
|
|
</el-form-item> |
|
|
|
|
|
|
|
|
</el-form> |
|
|
</el-form> |
|
|
<template #footer> |
|
|
<template #footer> |
|
|
<el-button @click="state.dialog.visible = false">取消</el-button> |
|
|
<el-button @click="state.dialog.visible = false">取消</el-button> |
|
|
@ -217,12 +167,7 @@ |
|
|
</el-dialog> |
|
|
</el-dialog> |
|
|
|
|
|
|
|
|
<!-- 详情弹窗 --> |
|
|
<!-- 详情弹窗 --> |
|
|
<el-dialog |
|
|
<el-dialog v-model="state.detailDialog.visible" title="审批流配置详情" width="800px" :destroy-on-close="true"> |
|
|
v-model="state.detailDialog.visible" |
|
|
|
|
|
title="审批流配置详情" |
|
|
|
|
|
width="800px" |
|
|
|
|
|
:destroy-on-close="true" |
|
|
|
|
|
> |
|
|
|
|
|
<el-descriptions :column="1" border> |
|
|
<el-descriptions :column="1" border> |
|
|
<el-descriptions-item label="ID"> |
|
|
<el-descriptions-item label="ID"> |
|
|
{{ state.detailDialog.info?.id || '-' }} |
|
|
{{ state.detailDialog.info?.id || '-' }} |
|
|
@ -246,19 +191,17 @@ |
|
|
<div class="mt-20px"> |
|
|
<div class="mt-20px"> |
|
|
<div class="font-bold text-16px mb-10px">审批节点列表</div> |
|
|
<div class="font-bold text-16px mb-10px">审批节点列表</div> |
|
|
<el-timeline> |
|
|
<el-timeline> |
|
|
<el-timeline-item |
|
|
<el-timeline-item v-for="(node, index) in state.detailDialog.info?.nodes || []" :key="index" |
|
|
v-for="(node, index) in state.detailDialog.info?.nodes || []" |
|
|
:type="getNodeType(node.sign_type)" :color="getNodeColor(node.sign_type)"> |
|
|
:key="index" |
|
|
|
|
|
:type="getNodeType(node.sign_type)" |
|
|
|
|
|
:color="getNodeColor(node.sign_type)" |
|
|
|
|
|
> |
|
|
|
|
|
<div class="font-bold mb-5px">{{ node.node_name }}</div> |
|
|
<div class="font-bold mb-5px">{{ node.node_name }}</div> |
|
|
<div class="text-gray-500"> |
|
|
<div class="text-gray-500"> |
|
|
审批人类型:{{ getApproverTypeText(node.approver_type) }} |
|
|
审批人类型:{{ getApproverTypeText(node.approver_type) }} |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="text-gray-500"> |
|
|
<div class="text-gray-500"> |
|
|
审批人:{{ node.approver_ids }} |
|
|
审批人:{{ getApproverNames(node.approver_ids,node.approver_type)}} |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="text-gray-500"> |
|
|
<div class="text-gray-500"> |
|
|
审批类型:{{ node.sign_type === 'or_sign' ? '或签' : '会签' }} |
|
|
审批类型:{{ node.sign_type === 'or_sign' ? '或签' : '会签' }} |
|
|
</div> |
|
|
</div> |
|
|
@ -274,6 +217,12 @@ import { reactive, ref, onMounted } from 'vue' |
|
|
import { ElMessage, ElMessageBox, FormInstance } from 'element-plus' |
|
|
import { ElMessage, ElMessageBox, FormInstance } from 'element-plus' |
|
|
import { getConfigList, getConfigInfo, addConfig, editConfig, deleteConfig, changeConfigStatus } from '@/app/api/school_approval/config' |
|
|
import { getConfigList, getConfigInfo, addConfig, editConfig, deleteConfig, changeConfigStatus } from '@/app/api/school_approval/config' |
|
|
|
|
|
|
|
|
|
|
|
import { |
|
|
|
|
|
person_all, |
|
|
|
|
|
role_all, |
|
|
|
|
|
departments_all |
|
|
|
|
|
} from '@/app/api/sys' |
|
|
|
|
|
|
|
|
// 移除draggable导入,暂时不使用拖拽功能 |
|
|
// 移除draggable导入,暂时不使用拖拽功能 |
|
|
// import draggable from 'vuedraggable' |
|
|
// import draggable from 'vuedraggable' |
|
|
// 移除i18n导入 |
|
|
// 移除i18n导入 |
|
|
@ -319,19 +268,9 @@ const state = reactive({ |
|
|
status: '' |
|
|
status: '' |
|
|
}, |
|
|
}, |
|
|
// 模拟数据,实际应该从API获取 |
|
|
// 模拟数据,实际应该从API获取 |
|
|
userOptions: [ |
|
|
userOptions: [], |
|
|
{ label: '用户1', value: '1' }, |
|
|
roleOptions: [], |
|
|
{ label: '用户2', value: '2' }, |
|
|
departmentOptions: [], |
|
|
{ label: '用户3', value: '3' } |
|
|
|
|
|
], |
|
|
|
|
|
roleOptions: [ |
|
|
|
|
|
{ label: '角色1', value: '1' }, |
|
|
|
|
|
{ label: '角色2', value: '2' } |
|
|
|
|
|
], |
|
|
|
|
|
departmentOptions: [ |
|
|
|
|
|
{ label: '部门1', value: '1' }, |
|
|
|
|
|
{ label: '部门2', value: '2' } |
|
|
|
|
|
], |
|
|
|
|
|
dialog: { |
|
|
dialog: { |
|
|
visible: false, |
|
|
visible: false, |
|
|
title: '', |
|
|
title: '', |
|
|
@ -359,6 +298,44 @@ const state = reactive({ |
|
|
} |
|
|
} |
|
|
}) |
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
const setPersonIdList = async () => { |
|
|
|
|
|
state.userOptions = await (await person_all()).data |
|
|
|
|
|
} |
|
|
|
|
|
setPersonIdList() |
|
|
|
|
|
|
|
|
|
|
|
const setRoleIdList = async () => { |
|
|
|
|
|
state.roleOptions = await (await role_all()).data |
|
|
|
|
|
} |
|
|
|
|
|
setRoleIdList() |
|
|
|
|
|
|
|
|
|
|
|
const setDepartmentsIdList = async () => { |
|
|
|
|
|
state.departmentOptions = await (await departments_all()).data |
|
|
|
|
|
} |
|
|
|
|
|
setDepartmentsIdList() |
|
|
|
|
|
|
|
|
|
|
|
const getApproverNames = (ids : string | string[], type : string) => { |
|
|
|
|
|
if (!ids) return ''; |
|
|
|
|
|
const idArray = typeof ids === 'string' ? ids.split(',') : ids; |
|
|
|
|
|
|
|
|
|
|
|
let options = []; |
|
|
|
|
|
if (type === 'user') { |
|
|
|
|
|
options = state.userOptions; |
|
|
|
|
|
} else if (type === 'role') { |
|
|
|
|
|
options = state.roleOptions; |
|
|
|
|
|
} else if (type === 'department') { |
|
|
|
|
|
options = state.departmentOptions; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
console.log(options); |
|
|
|
|
|
|
|
|
|
|
|
return idArray |
|
|
|
|
|
.map(id => { |
|
|
|
|
|
const match = options.find(item => String(item.id || item.role_id) === String(id)); |
|
|
|
|
|
return match ? (match.name || match.role_name || match.department_name) : ''; |
|
|
|
|
|
}) |
|
|
|
|
|
.filter(name => name !== '') |
|
|
|
|
|
.join(', '); |
|
|
|
|
|
}; |
|
|
// 校验节点 |
|
|
// 校验节点 |
|
|
function validateNodes(rule : any, value : any, callback : any) { |
|
|
function validateNodes(rule : any, value : any, callback : any) { |
|
|
if (!value || value.length === 0) { |
|
|
if (!value || value.length === 0) { |
|
|
|