first commit
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
<!--#
|
||||
layout("/layouts/platform.html"){
|
||||
#-->
|
||||
|
||||
<style>
|
||||
.design-dialog .el-dialog__body {
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<guava>
|
||||
<el-card shadow="never">
|
||||
<search @search="doSearch">
|
||||
<search-item label="分类名称">
|
||||
<el-input v-model="pageForm.name" placeholder="请输入分类名称" clearable></el-input>
|
||||
</search-item>
|
||||
</search>
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="never">
|
||||
<table-tool>
|
||||
<el-button type="primary" @click="onAdd" size="small" icon="el-icon-plus">新增</el-button>
|
||||
</table-tool>
|
||||
<el-table :data="tableData" @sort-change="pageOrder" style="width: 100%">
|
||||
<el-table-column type="index" width="50px" label="序号" :index="indexMethod"></el-table-column>
|
||||
<el-table-column prop="name" label="分类名称"></el-table-column>
|
||||
<el-table-column prop="categoryCount" label="关联流程数"></el-table-column>
|
||||
<el-table-column label="操作" fixed="right" width="450px">
|
||||
<template slot-scope="{row}">
|
||||
<el-button size="mini" type="primary" @click="onEdit(row)">编辑</el-button>
|
||||
<el-button type="danger" size="mini" @click="onDelete(row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!--#include("/layouts/pagination.html"){}#-->
|
||||
</el-card>
|
||||
</guava>
|
||||
|
||||
<el-dialog :title="formData.id ? '编辑' : '新增'" :visible.sync="dialogVisible" width="40%">
|
||||
<el-form :model="formData" ref="formRef" label-width="80px">
|
||||
<el-form-item label="类型名称" prop="name"
|
||||
:rules="{ required: true, message: '请输入类型名称', trigger: 'blur' }">
|
||||
<el-input v-model="formData.name" placeholder="请输入类型名称"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="picIcon" label="图片图标">
|
||||
<file-upload
|
||||
:value.sync="formData.picIcon"
|
||||
:upload_number="1"
|
||||
upload_mode="image"
|
||||
upload_result_category="interval"
|
||||
upload_result_type="url"
|
||||
></file-upload>
|
||||
</el-form-item>
|
||||
<el-form-item label="图标" prop="icon">
|
||||
<el-input v-model="formData.icon" placeholder="请输入图标"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="dialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="onSubmit">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#app",
|
||||
mixins: [initTableMixins],
|
||||
data() {
|
||||
return {
|
||||
dialogVisible: false,
|
||||
formData: {},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onAdd() {
|
||||
this.formData = {}
|
||||
this.dialogVisible = true
|
||||
},
|
||||
onEdit(row) {
|
||||
this.dialogVisible = true
|
||||
this.formData = { ...row }
|
||||
},
|
||||
onSubmit() {
|
||||
this.$axios.post("/flow/category/submit", this.formData).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.$message.success(res.msg)
|
||||
this.pageData()
|
||||
this.dialogVisible = false
|
||||
}
|
||||
})
|
||||
},
|
||||
onDelete(row) {
|
||||
this.$confirm("您确定要删除吗?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(() => {
|
||||
this.$axios.post("/flow/category/delete", { id: row.id }).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$message.success(res.msg)
|
||||
this.pageData()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.pageData()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -0,0 +1,49 @@
|
||||
<!--#
|
||||
layout("/layouts/v4/baseLayout.html"){
|
||||
#-->
|
||||
|
||||
<div id="flowCommonApprovalForm" v-cloak>
|
||||
<snaker-flow
|
||||
:task_id="taskId"
|
||||
:instance_id="instanceId"
|
||||
:business_id="businessId"
|
||||
:pjax_urls="{
|
||||
applicationInfo: '/platform/article/write/index_',
|
||||
taskForm: '/platform/article/write/index_'
|
||||
}"
|
||||
:pjax_config="{
|
||||
push: false,
|
||||
replace: false,
|
||||
timeout: 10000
|
||||
}"
|
||||
></snaker-flow>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#flowCommonApprovalForm",
|
||||
data() {
|
||||
return {
|
||||
taskId: null,
|
||||
instanceId: null,
|
||||
businessId: null,
|
||||
formConfig: {}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleTaskSubmitted() {},
|
||||
handleCancel() {
|
||||
window.history.back()
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.taskId = new URLSearchParams(window.location.search).get("taskId")
|
||||
this.instanceId = new URLSearchParams(window.location.search).get("instanceId")
|
||||
this.businessId = new URLSearchParams(window.location.search).get("businessId")
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -0,0 +1,170 @@
|
||||
<!--#
|
||||
layout("/layouts/platform.html"){
|
||||
#-->
|
||||
|
||||
<style>
|
||||
.design-dialog .el-dialog__body {
|
||||
padding: 0;
|
||||
}
|
||||
.el-table__row--level-1 {
|
||||
background-color: #FDF5E6 !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<guava>
|
||||
<el-card shadow="never">
|
||||
<search @search="doSearch">
|
||||
<search-item label="流程名称">
|
||||
<el-input v-model="pageForm.displayName" placeholder="请输入流程名称" clearable></el-input>
|
||||
</search-item>
|
||||
<search-item label="流程编码">
|
||||
<el-input v-model="pageForm.name" placeholder="请输入流程编码" clearable></el-input>
|
||||
</search-item>
|
||||
<search-item label="流程分类">
|
||||
<el-select v-model="pageForm.category" placeholder="请选择流程分类" style="width: 100%"
|
||||
@change="doSearch" clearable>
|
||||
<el-option v-for="item in categoryOptions" :label="item.name" :value="item.id" :key="item.id"></el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
</search>
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="never">
|
||||
<table-tool></table-tool>
|
||||
<el-table :data="tableData" @sort-change="pageOrder" style="width: 100%"
|
||||
row-key="id" :tree-props="{children: 'children', hasChildren: 'hasChildren'}">
|
||||
<el-table-column label="序号" type="index" width="60">
|
||||
<template v-slot="{ row }">
|
||||
{{ row.rowNum }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
:label="column.label"
|
||||
:prop="column.prop"
|
||||
:key="column.prop"
|
||||
:width="column.width"
|
||||
:sortable="column.sortable"
|
||||
align="center"
|
||||
header-align="center"
|
||||
show-overflow-tooltip
|
||||
v-for="column in tableColumns"
|
||||
>
|
||||
<template v-slot="{ row }" v-if="column.prop === 'categoryName'">
|
||||
{{ categoryOptions.find(item => item.id === row.category)?.name }}
|
||||
</template>
|
||||
<template v-slot="{ row }" v-else-if="column.prop === 'state'">
|
||||
<el-tag size="mini" v-if="row.state===1" type="success">启用</el-tag>
|
||||
<el-tag size="mini" v-else-if="row.state===0" type="info">停用</el-tag>
|
||||
</template>
|
||||
<template v-slot="{ row }" v-else-if="column.prop === 'createTime'">
|
||||
{{ $moment(row.createdAt).format('YYYY-MM-DD HH:mm:ss') }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" fixed="right" width="350px">
|
||||
<template slot-scope="{row}">
|
||||
<el-button type="primary" size="mini" @click="onView(row)">查看</el-button>
|
||||
<el-button v-if="row.state===1" type="danger" size="mini" @click="onDisable(row)">停用</el-button>
|
||||
<el-button v-if="row.state===0" type="primary" size="mini" @click="onEnable(row)">启用</el-button>
|
||||
<el-button v-if="row.state===0" type="danger" size="mini" @click="onDelete(row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!--#include("/layouts/pagination.html"){}#-->
|
||||
</el-card>
|
||||
</guava>
|
||||
|
||||
<el-dialog title="查看流程图" :visible.sync="designVisible" class="design-dialog" width="80%">
|
||||
<div style="height: calc(100vh - 150px); width: 100%">
|
||||
<iframe v-if="designVisible" :src="designUrl" frameborder="0" height="100%" style="height: 100%; width: inherit"></iframe>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#app",
|
||||
mixins: [initTableMixins],
|
||||
data() {
|
||||
return {
|
||||
categoryOptions: [],
|
||||
designVisible: false,
|
||||
designUrl: null,
|
||||
tableColumns: [
|
||||
{prop: 'displayName', label: '流程定义名称'},
|
||||
{prop: 'name', label: '流程定义编码'},
|
||||
{prop: 'categoryName', label: '流程分类'},
|
||||
{prop: 'version', label: '版本号'},
|
||||
{prop: 'state', label: '状态'},
|
||||
{prop: 'createTime', label: '创建时间'},
|
||||
],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onView(row) {
|
||||
this.designVisible = true
|
||||
this.designUrl = "/flow/define/preview?defineId=" + row.id
|
||||
},
|
||||
|
||||
onDisable(row) {
|
||||
this.$confirm("确定要停用该流程吗?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(() => {
|
||||
this.$axios.post("/flow/define/disable", { id: row.id }).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$message.success("停用成功")
|
||||
this.pageData()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
onEnable(row) {
|
||||
this.$confirm("确定要启用该流程吗?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(() => {
|
||||
this.$axios.post("/flow/define/enable", { id: row.id }).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$message.success("启用成功")
|
||||
this.pageData()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
onDelete(row) {
|
||||
this.$confirm("您确定要删除吗", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(() => {
|
||||
this.$axios.post("/flow/define/delete", { id: row.id }).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$message.success(res.msg)
|
||||
this.pageData()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
listCategory() {
|
||||
this.$axios.post("/flow/category/list").then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.categoryOptions = res.data
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.pageData()
|
||||
this.listCategory()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -0,0 +1,350 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0"/>
|
||||
<title>流程设计器</title>
|
||||
<script src="/assets/platform/plugins/vue/vue.js"></script>
|
||||
<script src="/assets/platform/plugins/jquery/jquery.js"></script>
|
||||
<script src="/assets/platform/plugins/element-ui/lib/index.js"></script>
|
||||
<link rel="stylesheet" href="${base!}/assets/platform/plugins/element-ui/lib/theme-chalk/index.css"/>
|
||||
<link rel="stylesheet" href="${base!}/assets/platform/plugins/element-ui/lib/theme-chalk/index.css"/>
|
||||
<link rel="stylesheet" href="${base!}/assets/platform/plugins/element-ui/lib/theme-chalk/override.css"/>
|
||||
<!-- 引入 core 包和对应 css-->
|
||||
<script src="/assets/platform/plugins/logicflow/logic-flow.js"></script>
|
||||
<link rel="stylesheet" href="/assets/platform/plugins/logicflow/index.css"/>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@logicflow/extension@2.1.4/dist/index.min.js"></script>
|
||||
<script src="/assets/platform/plugins/snaker/SnakerflowDesigner.umd.js"></script>
|
||||
<style>
|
||||
#snaker-flow-preview {
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.approval-card {
|
||||
position: absolute;
|
||||
width: 320px;
|
||||
background: #ffffff;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #d9e3f0;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
||||
z-index: 1000;
|
||||
font-family: "Microsoft YaHei", "PingFang SC", sans-serif;
|
||||
transform: translate(10px, 10px);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.tab-container {
|
||||
border-bottom: 1px solid #e8e8e8;
|
||||
}
|
||||
|
||||
.tab-header {
|
||||
display: flex;
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
.tab-item {
|
||||
padding: 8px 16px;
|
||||
cursor: pointer;
|
||||
border-right: 1px solid #e8e8e8;
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
background: #fafafa;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.tab-item:last-child {
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
.tab-item.active {
|
||||
background: #fff;
|
||||
color: #333;
|
||||
border-bottom: 2px solid #1890ff;
|
||||
margin-bottom: -1px;
|
||||
}
|
||||
|
||||
.tab-item:hover {
|
||||
background: #f0f0f0;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
/* 卡片标题栏(OA风格顶部色条) */
|
||||
.approval-card .card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 12px 16px;
|
||||
background: #1a73e8;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.approval-card .card-header h3 {
|
||||
margin: 0;
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.approval-card .card-header button {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
border: none;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border-radius: 50%;
|
||||
color: white;
|
||||
font-size: 16px;
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.approval-card .card-header button:hover {
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
/* 卡片内容区域 */
|
||||
.approval-card .card-body {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
/* 信息行样式 */
|
||||
.approval-card .info-row {
|
||||
display: flex;
|
||||
margin-bottom: 12px;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.approval-card .info-label {
|
||||
width: 80px;
|
||||
color: #666;
|
||||
font-size: 13px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.approval-card .info-value {
|
||||
flex: 1;
|
||||
color: #333;
|
||||
font-size: 13px;
|
||||
line-height: 1.5;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
/*!* 分隔线 *!*/
|
||||
/*.approval-card .divider {*/
|
||||
/* height: 1px;*/
|
||||
/* background: #f0f0f0;*/
|
||||
/* margin: 12px 0;*/
|
||||
/*}*/
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="snaker-flow-preview">
|
||||
<snaker-flow-designer
|
||||
ref="designer"
|
||||
v-model="flowData"
|
||||
:show-doc="false"
|
||||
:viewer="true"
|
||||
node-render-type="html"
|
||||
:high-light="highLight"
|
||||
></snaker-flow-designer>
|
||||
|
||||
<div
|
||||
v-if="showApprovalCard"
|
||||
class="approval-card"
|
||||
:style="{
|
||||
left: cardPosition.x+'px',
|
||||
top: cardPosition.y+'px'
|
||||
}"
|
||||
>
|
||||
<div class="card-header">
|
||||
<h3>详情</h3>
|
||||
<button @click="closeCard">×</button>
|
||||
</div>
|
||||
<!-- Tab切换 -->
|
||||
<div class="tab-container" v-if="approvalInfos.length > 1">
|
||||
<div class="tab-header">
|
||||
<div
|
||||
v-for="(item, index) in approvalInfos"
|
||||
:key="index"
|
||||
class="tab-item"
|
||||
:class="{active: activeTabIndex === index}"
|
||||
@click="activeTabIndex = index"
|
||||
>
|
||||
记录{{index + 1}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body">
|
||||
<div v-for="(approvalInfo, index) in approvalInfos" :key="index" v-show="activeTabIndex === index">
|
||||
<div class="info-row">
|
||||
<span class="info-label">节点类型:</span>
|
||||
<span class="info-value">{{approvalInfo.displayName}}</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">审批人:</span>
|
||||
<span class="info-value" v-if="currentNode.id === 'startTask'">
|
||||
{{approvalInfo.ext?.initiatorName}}({{approvalInfo.ext?.initiatorAccount}})
|
||||
</span>
|
||||
<span class="info-value"
|
||||
v-else>{{approvalInfo.taskFormData.userName}}({{approvalInfo.taskFormData?.loginName}})</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">审核状态:</span>
|
||||
<span class="info-value">{{getTaskStateText(approvalInfo.taskState)}}</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">提交结果:</span>
|
||||
<span class="info-value">{{getSubmitTypeText(approvalInfo.ext.submitType)}}</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">提交意见:</span>
|
||||
<span class="info-value">{{approvalInfo.taskFormData.opinion}}</span>
|
||||
</div>
|
||||
<!-- <div class="divider"></div>-->
|
||||
<div class="info-row">
|
||||
<span class="info-label">提交时间:</span>
|
||||
<span class="info-value">{{approvalInfo.finishTime}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
<script nonce="${cspNonce!}">
|
||||
Vue.use(SnakerflowDesigner.default)
|
||||
const vue = new Vue({
|
||||
el: "#snaker-flow-preview",
|
||||
data() {
|
||||
return {
|
||||
// 流程定义ID
|
||||
defineId: "${defineId!}",
|
||||
// 流程实例ID
|
||||
instanceId: "${instanceId!}",
|
||||
// 流程定义数据
|
||||
flowData: {},
|
||||
// 高亮数据
|
||||
highLight: {},
|
||||
// 历史审批记录
|
||||
hisApproval: [],
|
||||
// 展示已审核信息
|
||||
showApprovalCard: false,
|
||||
// 审批信息卡片位置
|
||||
cardPosition: {x: 0, y: 0},
|
||||
// 当前节点
|
||||
currentNode: [],
|
||||
// 审批信息数组
|
||||
approvalInfos: [],
|
||||
// 当前选中的tab索引
|
||||
activeTabIndex: 0
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// approvalInfo() {
|
||||
// if (this.currentNode) {
|
||||
// return this.hisApproval.find((item) => item.taskName === this.currentNode.id)
|
||||
// }
|
||||
// }
|
||||
},
|
||||
methods: {
|
||||
getDetail() {
|
||||
$.get("/flow/define/detail", {id: this.defineId}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.flowData = res.data.content
|
||||
this.initNodeEvent()
|
||||
}
|
||||
})
|
||||
},
|
||||
getHighLight() {
|
||||
$.get("/flow/common/instanceHighLight", {instanceId: this.instanceId}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.highLight = res.data
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
getHisApproval() {
|
||||
$.get("/flow/common/approvalRecord", {instanceId: this.instanceId}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.hisApproval = res.data
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
initNodeEvent() {
|
||||
this.$nextTick(() => {
|
||||
console.log(this.$refs.designer.lf.graphModel.eventCenter)
|
||||
this.$refs.designer.lf.graphModel.eventCenter.on("node:click", ({e, data}) => {
|
||||
console.log(data)
|
||||
console.log(e)
|
||||
|
||||
// 获取点击位置(考虑页面滚动情况)
|
||||
const scrollX = window.scrollX || window.pageXOffset
|
||||
const scrollY = window.scrollY || window.pageYOffset
|
||||
|
||||
this.cardPosition = {
|
||||
x: e.clientX + scrollX,
|
||||
y: e.clientY + scrollY
|
||||
}
|
||||
|
||||
if (data.type !== "snaker:task") return
|
||||
|
||||
const approvalInfos = this.hisApproval.filter((item) => item.taskName === data.id && item.taskState === 20)
|
||||
|
||||
if (approvalInfos && approvalInfos.length > 0) {
|
||||
this.approvalInfos = approvalInfos
|
||||
this.currentNode = data
|
||||
this.activeTabIndex = 0
|
||||
this.showApprovalCard = true
|
||||
}
|
||||
})
|
||||
|
||||
this.$refs.designer.lf.graphModel.eventCenter.on("blank:click", (args) => {
|
||||
this.closeCard()
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
closeCard() {
|
||||
this.showApprovalCard = false
|
||||
this.activeTabIndex = 0
|
||||
},
|
||||
|
||||
// 获取任务状态文本
|
||||
getTaskStateText(taskState) {
|
||||
const stateMap = {
|
||||
10: "进行中",
|
||||
20: "已完成",
|
||||
30: "已撤回"
|
||||
}
|
||||
return stateMap[taskState] || taskState
|
||||
},
|
||||
|
||||
// 获取提交结果文本
|
||||
getSubmitTypeText(submitType) {
|
||||
const typeMap = {
|
||||
0: "发起申请",
|
||||
1: "同意申请",
|
||||
2: "拒绝申请",
|
||||
3: "退回上一步",
|
||||
4: "跳转",
|
||||
5: "重新提交",
|
||||
6: "退回发起人",
|
||||
20: "拒绝申请"
|
||||
}
|
||||
return typeMap[submitType] || submitType
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (this.defineId) {
|
||||
this.getDetail()
|
||||
}
|
||||
if (this.instanceId) {
|
||||
this.getHighLight()
|
||||
this.getHisApproval()
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
</html>
|
||||
@@ -0,0 +1,185 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>流程设计</title>
|
||||
<link rel="stylesheet" href="/assets/platform/plugins/snaker/snaker.css" type="text/css" media="all" />
|
||||
</head>
|
||||
<body class="pear-container">
|
||||
<div id="toolbox">
|
||||
<div id="toolbox_handle">工具集</div>
|
||||
<div class="node" id="save">
|
||||
<img src="/assets/platform/plugins/snaker/images/save.gif" />
|
||||
保存
|
||||
</div>
|
||||
<div>
|
||||
<hr />
|
||||
</div>
|
||||
<div class="node selectable" id="pointer">
|
||||
<img src="/assets/platform/plugins/snaker/images/select16.gif" />
|
||||
Select
|
||||
</div>
|
||||
<div class="node selectable" id="path">
|
||||
<img src="/assets/platform/plugins/snaker/images/16/flow_sequence.png" />
|
||||
transition
|
||||
</div>
|
||||
<div>
|
||||
<hr />
|
||||
</div>
|
||||
<div class="node state" id="start" type="start">
|
||||
<img src="/assets/platform/plugins/snaker/images/16/start_event_empty.png" />
|
||||
start
|
||||
</div>
|
||||
<div class="node state" id="end" type="end">
|
||||
<img src="/assets/platform/plugins/snaker/images/16/end_event_terminate.png" />
|
||||
end
|
||||
</div>
|
||||
<div class="node state" id="task" type="task">
|
||||
<img src="/assets/platform/plugins/snaker/images/16/task_empty.png" />
|
||||
task
|
||||
</div>
|
||||
<div class="node state" id="task" type="custom">
|
||||
<img src="/assets/platform/plugins/snaker/images/16/task_empty.png" />
|
||||
custom
|
||||
</div>
|
||||
<div class="node state" id="task" type="subprocess">
|
||||
<img src="/assets/platform/plugins/snaker/images/16/task_empty.png" />
|
||||
subprocess
|
||||
</div>
|
||||
<div class="node state" id="fork" type="decision">
|
||||
<img src="/assets/platform/plugins/snaker/images/16/gateway_exclusive.png" />
|
||||
decision
|
||||
</div>
|
||||
<div class="node state" id="fork" type="fork">
|
||||
<img src="/assets/platform/plugins/snaker/images/16/gateway_parallel.png" />
|
||||
fork
|
||||
</div>
|
||||
<div class="node state" id="join" type="join">
|
||||
<img src="/assets/platform/plugins/snaker/images/16/gateway_parallel.png" />
|
||||
join
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="properties">
|
||||
<div id="properties_handle">属性</div>
|
||||
<table class="properties_all" cellpadding="0" cellspacing="0"></table>
|
||||
<div> </div>
|
||||
</div>
|
||||
|
||||
<div id="snakerflow"></div>
|
||||
|
||||
<script src="/assets/platform/plugins/jquery/jquery.js"></script>
|
||||
<script src="/assets/platform/plugins/snaker/raphael-min.js" type="text/javascript"></script>
|
||||
<script src="/assets/platform/plugins/snaker/jquery-ui-1.8.4.custom/js/jquery.min.js" type="text/javascript"></script>
|
||||
<script src="/assets/platform/plugins/snaker/jquery-ui-1.8.4.custom/js/jquery-ui.min.js" type="text/javascript"></script>
|
||||
<script src="/assets/platform/plugins/snaker/dialog.js" type="text/javascript"></script>
|
||||
<script src="/assets/platform/plugins/snaker/snaker.designer.js" type="text/javascript"></script>
|
||||
<script src="/assets/platform/plugins/snaker/snaker.model.js" charset="utf-8" type="text/javascript"></script>
|
||||
<script src="/assets/platform/plugins/snaker/snaker.editors.js" type="text/javascript"></script>
|
||||
<script nonce="${cspNonce!}">
|
||||
const processId = "${processId!}"
|
||||
console.log(processId)
|
||||
|
||||
console.log(new URLSearchParams(window.location.search).get("processId"))
|
||||
|
||||
$.post("/snakerflow/define//process/modelJson", { processId }).then((res) => {
|
||||
console.log(res)
|
||||
if (res.code === 0) {
|
||||
let model = res.data
|
||||
if (model) {
|
||||
model = eval("(" + model + ")")
|
||||
}
|
||||
$("#snakerflow").snakerflow({
|
||||
basePath: "/assets/platform/plugins/snaker/",
|
||||
ctxPath: "/",
|
||||
restore: model,
|
||||
userJson: {},
|
||||
formPath: "forms/",
|
||||
tools: {
|
||||
save: {
|
||||
onclick: function (data) {
|
||||
saveModel(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
function saveModel(data) {
|
||||
$.post("/snakerflow/define/saveProcessXml", { model: data, id: processId }).then((res) => {
|
||||
if (res.code === 0) {
|
||||
// alert("保存成功")
|
||||
window.parent.postMessage("success")
|
||||
} else {
|
||||
window.parent.postMessage("error")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// layui.use(['table', 'form', 'jquery', 'common', 'easyAdmin'], function () {
|
||||
// let easyAdmin = layui.easyAdmin;
|
||||
// id = getQueryString("processId");
|
||||
// easyAdmin.httpGet("/flow/process/modelJson?processId=" + id, function (data) {
|
||||
// var model = "";
|
||||
// if (data) {
|
||||
// model = eval("(" + data + ")");
|
||||
// }
|
||||
// var userJson = {};
|
||||
// easyAdmin.httpGet("/sys/user/getAll", function (result) {
|
||||
// if (result.success) {
|
||||
// userJson = result.data;
|
||||
// }
|
||||
// }, true, false);
|
||||
//
|
||||
// var isSubmitting = false; // 添加一个变量用于标记是否正在提交中
|
||||
//
|
||||
// $('#snakerflow').snakerflow({
|
||||
// basePath: "/assets/platform/plugins/snaker/",
|
||||
// ctxPath: "/",
|
||||
// restore: model,
|
||||
// userJson: userJson,
|
||||
// formPath: "forms/",
|
||||
// tools: {
|
||||
// save: {
|
||||
// onclick: function (data) {
|
||||
// if (isSubmitting) {
|
||||
// return false; // 如果正在提交中,则不执行后续代码
|
||||
// }
|
||||
// isSubmitting = true; // 设置为正在提交中状态
|
||||
// saveModel(data);
|
||||
// isSubmitting = false; // 处理完成后重置提交状态
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// });
|
||||
//
|
||||
//
|
||||
// function getQueryString(name) {
|
||||
// var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
|
||||
// var r = window.location.search.substr(1).match(reg);
|
||||
// if (r !== null)
|
||||
// return unescape(r[2]);
|
||||
// return "";
|
||||
// }
|
||||
//
|
||||
//
|
||||
// // window.saveModel = function (data) {
|
||||
// // easyAdmin.http({
|
||||
// // type: 'POST',
|
||||
// // url: "/flow/process/deployXml",
|
||||
// // data: "model=" + data + "&id=" + id,
|
||||
// // async: false,
|
||||
// // globle: false,
|
||||
// // success: function (data) {
|
||||
// // parent.layer.close(parent.layer.getFrameIndex(window.name));//关闭当前页
|
||||
// // parent.layui.table.reload("user-table");
|
||||
// // }
|
||||
// // });
|
||||
// //
|
||||
// // }
|
||||
// })
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,235 @@
|
||||
<!--#
|
||||
layout("/layouts/platform.html"){
|
||||
#-->
|
||||
|
||||
<style>
|
||||
.design-dialog .el-dialog__body {
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<guava>
|
||||
<el-card shadow="never">
|
||||
<search @search="doSearch">
|
||||
<search-item label="名称">
|
||||
<el-input v-model="pageForm.displayName" placeholder="请输入名称" clearable></el-input>
|
||||
</search-item>
|
||||
<search-item label="编码">
|
||||
<el-input v-model="pageForm.name" placeholder="请输入编码" clearable></el-input>
|
||||
</search-item>
|
||||
</search>
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="never">
|
||||
<table-tool>
|
||||
<el-button type="primary" @click="onAdd" size="small" icon="el-icon-plus">新增</el-button>
|
||||
</table-tool>
|
||||
<el-table :data="tableData" @sort-change="pageOrder" style="width: 100%">
|
||||
<el-table-column type="index" width="50px" label="序号" :index="indexMethod"></el-table-column>
|
||||
<el-table-column prop="displayName" label="流程定义名称"></el-table-column>
|
||||
<el-table-column prop="name" label="流程定义编码"></el-table-column>
|
||||
<el-table-column prop="categoryName" label="流程分类">
|
||||
<template slot-scope="{row}">{{categoryOptions.find(item => item.id ===
|
||||
row.category)?.categoryName}}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="version" label="版本号"></el-table-column>
|
||||
<el-table-column prop="state" label="状态">
|
||||
<template slot-scope="{row}">
|
||||
<el-tag size="mini" v-if="row.state===1" type="success">启用</el-tag>
|
||||
<el-tag size="mini" v-else-if="row.state===0" type="info">停用</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" label="创建时间"></el-table-column>
|
||||
<el-table-column label="操作" fixed="right" width="350px">
|
||||
<template slot-scope="{row}">
|
||||
<el-button size="mini" type="primary" @click="onDesign(row)">设计</el-button>
|
||||
</el-button>
|
||||
<el-button size="mini" type="primary" @click="onEdit(row)">编辑</el-button>
|
||||
<!-- <el-button type="text" size="mini" @click="onView(row)">查看</el-button>-->
|
||||
<el-button v-if="row.state===1" type="danger" size="mini" @click="onUndeploy(row)">停用
|
||||
</el-button>
|
||||
<el-button v-if="row.state===0" type="primary" size="mini" @click="onPublish(row)">发布
|
||||
</el-button>
|
||||
<el-button v-if="row.state===0" type="danger" size="mini" @click="onDelete(row)">删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!--#include("/layouts/pagination.html"){}#-->
|
||||
</el-card>
|
||||
</guava>
|
||||
|
||||
<el-dialog :title="formData.id ? '编辑' : '新增'" :visible.sync="dialogVisible" width="800px">
|
||||
<el-form :model="formData" ref="formRef" label-width="120px">
|
||||
<el-form-item label="流程定义名称" prop="flowName" :rules="{ required: true, message: '请输入流程定义名称', trigger: 'blur' }">
|
||||
<el-input v-model="formData.flowName" placeholder="请输入流程定义名称"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="流程定义编码" prop="flowCode" :rules="{ required: true, message: '请输入流程定义编码', trigger: 'blur' }">
|
||||
<el-input v-model="formData.flowCode" placeholder="请输入流程定义编码"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="流程分类" prop="category" :rules="{ required: true, message: '请选择流程分类', trigger: 'change' }">
|
||||
<el-select v-model="formData.category" placeholder="请选择流程分类" clearable>
|
||||
<el-option v-for="item in categoryOptions" :key="item.id" :label="item.categoryName" :value="item.id"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="dialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="onSubmit">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog title="流程设计" :visible.sync="designVisible" fullscreen class="design-dialog">
|
||||
<div style="height: calc(100vh - 55px); width: 100%">
|
||||
<iframe v-if="designVisible" :src="designUrl" frameborder="0" height="100%"
|
||||
style="height: 100%; width: inherit"></iframe>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
|
||||
<el-dialog title="xml编辑" :visible.sync="xmlVisible" width="70%">
|
||||
<el-input type="textarea" style="width: 100%;" autosize v-model="formData.model"></el-input>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="xmlVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="onSave">保存</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#app",
|
||||
mixins: [initTableMixins],
|
||||
data() {
|
||||
return {
|
||||
dialogVisible: false,
|
||||
categoryOptions: [],
|
||||
designVisible: false,
|
||||
designUrl: null,
|
||||
xmlVisible: false,
|
||||
formData: {}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onAdd(){
|
||||
this.formData = {}
|
||||
this.dialogVisible = true
|
||||
},
|
||||
onSubmit(){
|
||||
$.post("/snakerflow/define/addProcess", this.formData)
|
||||
},
|
||||
|
||||
|
||||
onDesign(row = null) {
|
||||
this.designVisible = true
|
||||
this.iframeLoaded()
|
||||
this.designUrl = "/flow/define/designer2?processId=" + row?.id
|
||||
},
|
||||
|
||||
onEdit(row) {
|
||||
this.xmlVisible = true
|
||||
this.$axios.post("/snakerflow/define/getXml", { id: row.id }).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.formData = {
|
||||
id: row.id,
|
||||
model: res.data
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
onSave() {
|
||||
$.post("/snakerflow/define/saveProcessXml", { ...this.formData, xmlHeader: true }).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.$message.success("保存成功")
|
||||
this.pageData()
|
||||
this.xmlVisible = false
|
||||
} else {
|
||||
this.$message.error("保存失败")
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
iframeLoaded() {
|
||||
// iframe监听组件内设计器保存事件
|
||||
window.onmessage = (event) => {
|
||||
console.log(event)
|
||||
if (event.data === "success") {
|
||||
this.$message.success("保存成功")
|
||||
this.designVisible = false
|
||||
this.pageData()
|
||||
} else if (event.data === "error") {
|
||||
this.$message.error("保存失败")
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onUndeploy(row) {
|
||||
this.$confirm("您确定要停用吗", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(() => {
|
||||
this.$axios.post("/snakerflow/define/undeploy", { id: row.id }).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$message.success(res.msg)
|
||||
this.pageData()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
onPublish(row) {
|
||||
this.$confirm("您确定要发布吗", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(() => {
|
||||
this.$axios.post("/snakerflow/define/publish", { id: row.id }).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$message.success(res.msg)
|
||||
this.pageData()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
onDelete(row) {
|
||||
this.$confirm("您确定要删除吗", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(() => {
|
||||
this.$axios.post("/snakerflow/define/delete", { id: row.id }).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$message.success(res.msg)
|
||||
this.pageData()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
onView(row) {
|
||||
},
|
||||
|
||||
listCategory() {
|
||||
// this.$axios.get("/platform/warmFlow/category/list").then((res) => {
|
||||
// if (res.code === 0) {
|
||||
// this.categoryOptions = res.data
|
||||
// }
|
||||
// })
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.pageData()
|
||||
this.listCategory()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -0,0 +1,252 @@
|
||||
var assigneeForm = {
|
||||
template: /*language=HTML*/ `
|
||||
<el-form-item label="参与者">
|
||||
<div>
|
||||
<!-- 模式选择 -->
|
||||
<div style="margin-bottom: 10px;">
|
||||
<el-radio-group v-model="assigneeMode" @change="handleModeChange" size="small">
|
||||
<el-radio-button label="manual" :disabled="isFirstTaskNode">手动输入</el-radio-button>
|
||||
<el-radio-button label="select" :disabled="isFirstTaskNode">选择输入</el-radio-button>
|
||||
<el-radio-button label="initiator">流程发起人</el-radio-button>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
|
||||
<!-- 手动输入模式 -->
|
||||
<el-input
|
||||
v-if="assigneeMode === 'manual'"
|
||||
v-model="manualInput"
|
||||
placeholder="请输入参与者,多个参与者用逗号分隔"
|
||||
@change="updateModelValue">
|
||||
</el-input>
|
||||
|
||||
<!-- 选择输入模式 -->
|
||||
<el-input
|
||||
v-if="assigneeMode === 'select'"
|
||||
v-model="assigneeText"
|
||||
readonly
|
||||
style="width: 100%"
|
||||
placeholder="请选择参与者">
|
||||
<el-button
|
||||
slot="append"
|
||||
type="primary"
|
||||
style="color: #fff;background-color: var(--color-primary);border-color: var(--color-primary)"
|
||||
icon="el-icon-setting"
|
||||
@click="openUserDialog">
|
||||
选择
|
||||
</el-button>
|
||||
</el-input>
|
||||
|
||||
<!-- 流程发起人模式 -->
|
||||
<el-input
|
||||
v-if="assigneeMode === 'initiator'"
|
||||
value="initiator"
|
||||
readonly
|
||||
disabled
|
||||
style="width: 100%"
|
||||
placeholder="流程发起人">
|
||||
</el-input>
|
||||
</div>
|
||||
|
||||
<!-- 用户选择弹窗 -->
|
||||
<el-dialog title="选择参与者" :visible.sync="dialogVisible" width="80%" append-to-body top="20px">
|
||||
<div style="display: flex;">
|
||||
<!-- 左侧表格 -->
|
||||
<div style="flex: 3; margin-right: 10px; overflow: auto;">
|
||||
<div style="margin-bottom: 10px;">
|
||||
<el-input v-model="pageForm.searchKeyword" placeholder="请输入姓名或工号搜索" style="width: 200px; margin-right: 10px;"></el-input>
|
||||
<el-button type="primary" @click="searchUsers">搜索</el-button>
|
||||
</div>
|
||||
<el-table
|
||||
ref="userTableRef"
|
||||
:data="userList"
|
||||
border
|
||||
row-key="id"
|
||||
>
|
||||
<el-table-column type="selection" width="55" :reserve-selection="true"></el-table-column>
|
||||
<el-table-column prop="loginname" label="工号" width="100"></el-table-column>
|
||||
<el-table-column prop="username" label="姓名" width="120"></el-table-column>
|
||||
<el-table-column prop="unitName" label="单位"></el-table-column>
|
||||
</el-table>
|
||||
<div style="margin-top: 10px; text-align: right;">
|
||||
<el-pagination
|
||||
@current-change="handleCurrentChange"
|
||||
:current-page="pageForm.pageNumber"
|
||||
:page-size="pageForm.pageSize"
|
||||
layout="total, prev, pager, next, jumper"
|
||||
:total="pageForm.totalCount">
|
||||
</el-pagination>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 右侧已选列表 -->
|
||||
<div style="flex: 1; border: 1px solid #EBEEF5; border-radius: 4px; padding: 10px; overflow: auto;" v-if="$refs.userTableRef">
|
||||
<div style="font-weight: bold; margin-bottom: 10px;">已选择的参与者</div>
|
||||
<el-tag
|
||||
v-for="user in $refs.userTableRef.selection"
|
||||
:key="user.id"
|
||||
style="margin: 0 5px 5px 0;">
|
||||
{{ user.username }}
|
||||
</el-tag>
|
||||
<div v-if="$refs.userTableRef.selection.length === 0" style="color: #909399; font-size: 14px;">
|
||||
暂无选择的参与者
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="confirmSelection">确 定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</el-form-item>
|
||||
`,
|
||||
props: {
|
||||
model: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
field: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
start_node_next_node_ids: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
/**
|
||||
* 判断当前节点是否为第一个任务节点
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isFirstTaskNode() {
|
||||
return this.start_node_next_node_ids.includes(this.model.name)
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
assigneeMode: "manual",
|
||||
manualInput: "",
|
||||
assigneeText: "",
|
||||
dialogVisible: false,
|
||||
userList: [],
|
||||
selectedUsers: [],
|
||||
pageForm: {
|
||||
pageNumber: 1,
|
||||
pageSize: 10,
|
||||
searchKeyword: "",
|
||||
totalCount: 0
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// 回显
|
||||
this.initFromModel()
|
||||
},
|
||||
methods: {
|
||||
initFromModel() {
|
||||
const value = this.model[this.field]
|
||||
this.assigneeText = this.model["assigneeText"] || ""
|
||||
this.assigneeMode = this.model["assigneeMode"] || "manual"
|
||||
|
||||
if (this.assigneeMode === "initiator") {
|
||||
this.assignee = "initiator"
|
||||
this.assigneeText = "流程发起人"
|
||||
}
|
||||
|
||||
if (this.assigneeMode === "manual") {
|
||||
this.manualInput = value || ""
|
||||
}
|
||||
},
|
||||
|
||||
handleModeChange() {
|
||||
this.assigneeText = ""
|
||||
this.manualInput = ""
|
||||
this.assignee = ""
|
||||
|
||||
// 如果切换到流程发起人模式,直接设置值
|
||||
if (this.assigneeMode === "initiator") {
|
||||
this.assignee = "{$initiator}"
|
||||
this.assigneeText = "流程发起人"
|
||||
}
|
||||
|
||||
this.updateModelValue()
|
||||
},
|
||||
openUserDialog() {
|
||||
this.dialogVisible = true
|
||||
this.pageForm.pageNumber = 1
|
||||
this.pageForm.searchKeyword = ""
|
||||
this.loadSelectUsers()
|
||||
},
|
||||
|
||||
loadSelectUsers() {
|
||||
let userIds = this.model[this.field].split(",")
|
||||
$.get("/flow/design/assigneeEcho", { userIds: JSON.stringify(userIds) }).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.selectedUsers = res.data
|
||||
this.loadUsers()
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
loadUsers() {
|
||||
$.get("/flow/design/assigneePage", {
|
||||
...this.pageForm
|
||||
}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.userList = res.data.list
|
||||
this.pageForm.totalCount = res.data.totalCount
|
||||
// 设置已选中的行
|
||||
this.$nextTick(() => {
|
||||
this.setTableSelection()
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 设置表格选中数据
|
||||
setTableSelection() {
|
||||
// 如果当前表格中有该用户,选中TA
|
||||
this.userList.forEach((row) => {
|
||||
const exist = this.selectedUsers.map((item) => item.id).includes(row.id)
|
||||
if (exist) {
|
||||
this.$refs.userTableRef.toggleRowSelection(row, true)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
confirmSelection() {
|
||||
const selection = this.$refs.userTableRef.selection
|
||||
this.assignee = selection.map((item) => item.id).join(",")
|
||||
this.assigneeText = selection.map((item) => item.username).join(",")
|
||||
this.updateModelValue()
|
||||
this.dialogVisible = false
|
||||
},
|
||||
updateModelValue() {
|
||||
// 更新model中的值
|
||||
if (this.assigneeMode === "manual") {
|
||||
this.assignee = this.manualInput
|
||||
this.assigneeText = this.manualInput
|
||||
} else if (this.assigneeMode === "initiator") {
|
||||
this.assignee = "initiator"
|
||||
this.assigneeText = "流程发起人"
|
||||
}
|
||||
// 选择模式的处理在confirmSelection中
|
||||
|
||||
this.$set(this.model, this.field, this.assignee)
|
||||
this.$set(this.model, "assigneeText", this.assigneeText)
|
||||
this.$set(this.model, "assigneeMode", this.assigneeMode)
|
||||
},
|
||||
searchUsers() {
|
||||
this.pageForm.pageNumber = 1
|
||||
this.loadUsers()
|
||||
},
|
||||
handleSizeChange(val) {
|
||||
this.pageForm.pageSize = val
|
||||
this.loadUsers()
|
||||
},
|
||||
handleCurrentChange(val) {
|
||||
this.pageForm.pageNumber = val
|
||||
this.loadUsers()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
var buttonConfig = {
|
||||
template: /*language=HTML*/ `
|
||||
<el-form-item label="按钮配置">
|
||||
{{model}}
|
||||
<el-table :data="model['buttonConfig']" style="width: 100%" border>
|
||||
<!-- <el-table-column prop="value" label="值" width="120">-->
|
||||
<!-- <template slot-scope="{ row }">-->
|
||||
<!-- <el-input v-model="row.value" disabled></el-input>-->
|
||||
<!-- </template>-->
|
||||
<!-- </el-table-column>-->
|
||||
<el-table-column prop="originalText" label="原始文本" width="100"></el-table-column>
|
||||
<el-table-column prop="replacementText" label="替换文本">
|
||||
<template slot-scope="{ row }">
|
||||
<el-input v-model="row.replacementText" :disabled="row.disabled"></el-input>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="theme" label="主题">
|
||||
<template slot-scope="{ row }">
|
||||
<el-select v-model="row.theme" placeholder="请选择" :disabled="row.disabled">
|
||||
<el-option label="primary" value="primary"></el-option>
|
||||
<el-option label="success" value="success"></el-option>
|
||||
<el-option label="warning" value="warning"></el-option>
|
||||
<el-option label="danger" value="danger"></el-option>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="icon" label="图标" width="100">
|
||||
<template slot-scope="{ row }">
|
||||
<el-input v-model="row.icon" placeholder="请输入图标名称" :disabled="row.disabled"></el-input>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="visible" label="是否可见" width="100">
|
||||
<template slot-scope="{ row }">
|
||||
<el-switch v-model="row.visible" :disabled="row.disabled"></el-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-form-item>
|
||||
`,
|
||||
props: {
|
||||
model: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
// field: {
|
||||
// type: String,
|
||||
// required: true
|
||||
// }
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
tableData: [],
|
||||
button: {},
|
||||
defaultConfig: [
|
||||
{ value: 0, originalText: "发起申请" },
|
||||
{ value: 1, originalText: "同意申请" },
|
||||
{ value: 2, originalText: "拒绝申请" },
|
||||
{ value: 3, originalText: "退回上一步" },
|
||||
{ value: 4, originalText: "跳转" },
|
||||
{ value: 5, originalText: "重新提交" },
|
||||
{ value: 6, originalText: "退回发起人" },
|
||||
{ value: 20, originalText: "会签拒绝申请" }
|
||||
]
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
"model.buttonConfig": {
|
||||
handler(val) {
|
||||
this.$set(this.model, "buttonConfig", val)
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
"model.performType": {
|
||||
handler(val) {
|
||||
if (val === "ALL") {
|
||||
// 会签只有同意不同意
|
||||
this.$set(this.model, "buttonConfig", [
|
||||
{ value: 1, originalText: "同意", visible: true, disabled: true },
|
||||
{ value: 20, originalText: "不同意", visible: true, disabled: true }
|
||||
])
|
||||
} else {
|
||||
// 普通任务
|
||||
// const visibleConfigs = this.model.buttonConfig.filter((item) => item.visible)
|
||||
// if (visibleConfigs.length) {
|
||||
// this.$set(this.model, "buttonConfig", visibleConfigs)
|
||||
// } else {
|
||||
// this.$set(this.model, "buttonConfig", [
|
||||
// { value: 1, originalText: "同意", visible: true, disabled: false },
|
||||
// { value: 2, originalText: "拒绝", visible: true, disabled: false },
|
||||
// { value: 3, originalText: "退回上一步", visible: true, disabled: false },
|
||||
// { value: 4, originalText: "跳转", visible: true, disabled: false },
|
||||
// { value: 6, originalText: "退回发起人", visible: true, disabled: false }
|
||||
// ])
|
||||
// }
|
||||
}
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
"model.name": {
|
||||
handler(val) {
|
||||
if (val === "startTask") {
|
||||
// 申请只有发起申请
|
||||
this.$set(this.model, "buttonConfig", [{ value: 0, originalText: "提交", visible: true, disabled: false }])
|
||||
}
|
||||
},
|
||||
deep: true,
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
if (this.model["buttonConfig"] === undefined) {
|
||||
this.$set(this.model, "buttonConfig", this.defaultConfig)
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.init()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
|
||||
<title>流程设计器</title>
|
||||
<script src="/assets/platform/plugins/vue/vue.js"></script>
|
||||
<script src="/assets/platform/plugins/jquery/jquery.js"></script>
|
||||
<script src="/assets/platform/plugins/element-ui/lib/index.js"></script>
|
||||
<link rel="stylesheet" href="${base!}/assets/platform/plugins/element-ui/lib/theme-chalk/index.css" />
|
||||
<link rel="stylesheet" href="${base!}/assets/platform/plugins/element-ui/lib/theme-chalk/index_custom.css" />
|
||||
<link rel="stylesheet" href="${base!}/assets/platform/plugins/element-ui/lib/theme-chalk/override.css" />
|
||||
<link rel="stylesheet" href="${base!}/assets/platform/css/root.css" />
|
||||
<!-- 引入 core 包和对应 css-->
|
||||
<script src="/assets/platform/plugins/logicflow/logic-flow.js"></script>
|
||||
<link rel="stylesheet" href="/assets/platform/plugins/logicflow/index.css" />
|
||||
<!-- <script src="https://cdn.jsdelivr.net/npm/@logicflow/core@1.2.12/dist/logic-flow.js"></script>-->
|
||||
<!-- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@logicflow/core@1.2.12/dist/style/index.css" />-->
|
||||
<script src="/assets/platform/plugins/snaker/SnakerflowDesigner.umd.js"></script>
|
||||
<style>
|
||||
#app {
|
||||
height: 100vh;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<snaker-flow-designer
|
||||
ref="designer"
|
||||
v-model="flowData"
|
||||
@on-save="handleSave"
|
||||
:show-doc="false"
|
||||
node-render-type="html"
|
||||
:extend-property-keys="[
|
||||
'candidateUsers',
|
||||
'candidateGroups',
|
||||
'candidateHandler',
|
||||
'assigneeText',
|
||||
'assigneeMode',
|
||||
'buttonConfig',
|
||||
'enableNextOperator',
|
||||
'h5form'
|
||||
]"
|
||||
>
|
||||
<template v-slot:form-item-task-form="{model,field}">
|
||||
<el-form-item label="pc跳转地址">
|
||||
<el-input placeholder="请输入pc跳转地址" clearable v-model="model[field]"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="h5跳转地址">
|
||||
<el-input placeholder="请输入h5跳转地址" clearable v-model="model['h5form']"></el-input>
|
||||
</el-form-item>
|
||||
</template>
|
||||
|
||||
<template v-slot:form-item-task-assignee="{model,field}">
|
||||
<assignee-form :model="model" :field="field" :start_node_next_node_ids="startNodeNextNodeIds"></assignee-form>
|
||||
</template>
|
||||
|
||||
<template v-slot:form-item-task-assignment-handler="{model,field}">
|
||||
<el-form-item label="参与者处理类">
|
||||
<el-select v-model="model[field]" style="width: 100%" clearable :disabled="startNodeNextNodeIds.includes(model.name)">
|
||||
<el-option
|
||||
v-for="item in assignmentHandlerClassOptions"
|
||||
:key="item.value"
|
||||
:value="item.value"
|
||||
:label="item.name"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</template>
|
||||
|
||||
<template v-slot:form-item-task-candidate-handler="{model,field}">
|
||||
<el-form-item label="候选者处理类">
|
||||
<el-select v-model="model[field]" style="width: 100%" clearable :disabled="startNodeNextNodeIds.includes(model.name)">
|
||||
<el-option
|
||||
v-for="item in candidateHandlerClassOptions"
|
||||
:key="item.value"
|
||||
:value="item.value"
|
||||
:label="item.name"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</template>
|
||||
|
||||
<template v-slot="{model,field}">
|
||||
<el-form-item label="指定下一步处理人">
|
||||
<el-checkbox v-model="model['enableNextOperator']">指定下一步处理人</el-checkbox>
|
||||
</el-form-item>
|
||||
|
||||
<button-config :model="model" :field="field"></button-config>
|
||||
</template>
|
||||
|
||||
<!-- <template v-slot="{model,field}">-->
|
||||
<!-- <el-form-item label="表单查看URL">-->
|
||||
<!-- <el-input v-model="model[instanceViewUrl]"></el-input>-->
|
||||
<!-- </el-form-item>-->
|
||||
<!-- </template>-->
|
||||
</snaker-flow-designer>
|
||||
</div>
|
||||
</body>
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include('assigneeForm.js'){}#-->
|
||||
<!--#include('buttonConfig.js'){}#-->
|
||||
|
||||
Vue.use(SnakerflowDesigner.default)
|
||||
const vue = new Vue({
|
||||
el: "#app",
|
||||
components: {
|
||||
"assignee-form": assigneeForm,
|
||||
"button-config": buttonConfig
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
id: "${id!}",
|
||||
designerData: {},
|
||||
flowData: {},
|
||||
assignmentHandlerClassOptions: [],
|
||||
candidateHandlerClassOptions: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
startNodeNextNodeIds() {
|
||||
if (this.$refs.designer && this.$refs.designer.lf) {
|
||||
const graphData = this.$refs.designer.lf.getGraphData()
|
||||
if (graphData) {
|
||||
const { nodes, edges } = graphData
|
||||
const startNode = nodes.find((v) => v.type === "snaker:start")
|
||||
if (startNode) {
|
||||
const targetNodeIds = edges.filter((v) => v.sourceNodeId === startNode.id).map((v) => v.targetNodeId)
|
||||
return targetNodeIds
|
||||
}
|
||||
}
|
||||
}
|
||||
return []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleSave(val) {
|
||||
const design = {
|
||||
...this.designerData,
|
||||
content: val.json
|
||||
}
|
||||
$.post("/flow/design/updateContent", { design: JSON.stringify(design) }).then((res) => {
|
||||
if (res.code === 0) {
|
||||
window.parent.postMessage("success")
|
||||
} else {
|
||||
window.parent.postMessage("error")
|
||||
}
|
||||
})
|
||||
},
|
||||
getDetail() {
|
||||
$.get("/flow/design/detail", { id: this.id }).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.designerData = res.data
|
||||
if (res.data.content) {
|
||||
this.flowData = res.data.content
|
||||
} else {
|
||||
this.flowData = {}
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
init() {
|
||||
$.get("/flow/design/assigmentHandlerClass").then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.assignmentHandlerClassOptions = res.data
|
||||
}
|
||||
})
|
||||
$.get("/flow/design/candidateHandlerClass").then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.candidateHandlerClassOptions = res.data
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
getData() {
|
||||
console.log(this.$refs.designer)
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.init()
|
||||
},
|
||||
mounted() {
|
||||
if (this.id) {
|
||||
this.getDetail()
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
</html>
|
||||
@@ -0,0 +1,250 @@
|
||||
<!--#
|
||||
layout("/layouts/platform.html"){
|
||||
#-->
|
||||
|
||||
<style>
|
||||
.design-dialog .el-dialog__body {
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<guava>
|
||||
<el-card shadow="never">
|
||||
<search @search="doSearch">
|
||||
<search-item label="流程名称">
|
||||
<el-input v-model="pageForm.displayName" placeholder="请输入流程名称" clearable></el-input>
|
||||
</search-item>
|
||||
<search-item label="流程编码">
|
||||
<el-input v-model="pageForm.name" placeholder="请输入流程编码" clearable></el-input>
|
||||
</search-item>
|
||||
<search-item label="流程分类">
|
||||
<el-select v-model="pageForm.category" placeholder="请选择流程分类" style="width: 100%"
|
||||
@change="doSearch" clearable>
|
||||
<el-option v-for="item in categoryOptions" :label="item.name" :value="item.id" :key="item.id"></el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
<search-item label="是否部署">
|
||||
<el-select v-model="pageForm.deployed" placeholder="请选择是否部署" style="width: 100%"
|
||||
@change="doSearch" clearable>
|
||||
<el-option label="全部" :value="null"></el-option>
|
||||
<el-option label="已部署" :value="true"></el-option>
|
||||
<el-option label="未部署" :value="false"></el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
</search>
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="never">
|
||||
<table-tool>
|
||||
<el-button type="primary" @click="onAdd" size="small" icon="el-icon-plus">新增</el-button>
|
||||
</table-tool>
|
||||
<el-table :data="tableData" @sort-change="pageOrder" style="width: 100%">
|
||||
<el-table-column type="index" width="50px" label="序号" :index="indexMethod"></el-table-column>
|
||||
<el-table-column prop="displayName" label="流程定义名称"></el-table-column>
|
||||
<el-table-column prop="name" label="流程定义编码"></el-table-column>
|
||||
<el-table-column prop="category" label="流程分类">
|
||||
<template slot-scope="{row}">
|
||||
{{categoryOptions.find(v=>v.id === row.category)?.name}}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="isDeployed" label="是否部署">
|
||||
<template slot-scope="{row}">
|
||||
<el-tag size="mini" v-if="row.isDeployed===1" type="success">是</el-tag>
|
||||
<el-tag size="mini" v-else-if="row.isDeployed===0" type="info">否</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" fixed="right" width="450px">
|
||||
<template slot-scope="{row}">
|
||||
<el-button size="mini" type="primary" @click="onDesign(row)">设计</el-button>
|
||||
</el-button>
|
||||
<el-button size="mini" type="primary" @click="onEdit(row)">编辑</el-button>
|
||||
<!-- v-if="row.isDeployed===0"-->
|
||||
<el-button type="primary" size="mini" @click="onDeploy(row)">部署
|
||||
</el-button>
|
||||
<el-button type="danger" size="mini" @click="onDelete(row)">删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!--#include("/layouts/pagination.html"){}#-->
|
||||
</el-card>
|
||||
</guava>
|
||||
|
||||
<el-dialog :title="formData.id ? '编辑' : '新增'" :visible.sync="dialogVisible" width="70%">
|
||||
<el-form :model="formData" ref="formRef" label-width="120px">
|
||||
<el-form-item label="流程定义名称" prop="displayName"
|
||||
:rules="{ required: true, message: '请输入流程定义名称', trigger: 'blur' }">
|
||||
<el-input v-model="formData.displayName" placeholder="请输入流程定义名称"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="流程定义编码" prop="name"
|
||||
:rules="{ required: true, message: '请输入流程定义编码', trigger: 'blur' }">
|
||||
<el-input v-model="formData.name" placeholder="请输入流程定义编码"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="流程分类" prop="category"
|
||||
:rules="{ required: false, message: '请选择流程分类', trigger: 'change' }"
|
||||
style="width: 100%">
|
||||
<el-select v-model="formData.category" placeholder="请选择流程分类" clearable style="width: 100%">
|
||||
<el-option v-for="item in categoryOptions" :key="item.id" :label="item.name"
|
||||
:value="item.id"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="电脑端发起地址" prop="instanceUrl">
|
||||
<el-input v-model="formData.instanceUrl" placeholder="请输入电脑端发起地址"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="手机端发起地址" prop="h5InstanceUrl">
|
||||
<el-input v-model="formData.h5InstanceUrl" placeholder="请输入手机端发起地址"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="电脑端查看地址" prop="instanceViewUrl">
|
||||
<el-input v-model="formData.instanceViewUrl" placeholder="请输入电脑端发起地址"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="手机端查看地址" prop="h5InstanceViewUrl">
|
||||
<el-input v-model="formData.h5InstanceViewUrl" placeholder="请输入手机端发起地址"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="picIcon" label="图片图标">
|
||||
<file-upload
|
||||
:value.sync="formData.picIcon"
|
||||
:upload_number="1"
|
||||
upload_mode="image"
|
||||
upload_result_category="interval"
|
||||
upload_result_type="url"
|
||||
></file-upload>
|
||||
</el-form-item>
|
||||
<el-form-item label="图标" prop="icon">
|
||||
<el-input v-model="formData.icon" placeholder="请输入图标"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="说明" prop="description">
|
||||
<text-editor v-model="formData.description"></text-editor>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="dialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="onSubmit">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog title="流程设计" :visible.sync="designVisible" fullscreen class="design-dialog">
|
||||
<div style="height: calc(100vh - 55px); width: 100%">
|
||||
<iframe v-if="designVisible" :src="designUrl" frameborder="0" height="100%"
|
||||
style="height: 100%; width: inherit"></iframe>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#app",
|
||||
mixins: [initTableMixins],
|
||||
data() {
|
||||
return {
|
||||
dialogVisible: false,
|
||||
categoryOptions: [],
|
||||
designVisible: false,
|
||||
designUrl: null,
|
||||
formData: {},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onAdd() {
|
||||
this.formData = {}
|
||||
this.dialogVisible = true
|
||||
},
|
||||
onEdit(row) {
|
||||
this.dialogVisible = true
|
||||
this.formData = { ...row }
|
||||
},
|
||||
onSubmit() {
|
||||
$.post("/flow/design/" + (this.formData.id ? "update" : "insert"), { design: JSON.stringify(this.formData) }).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.$message.success(res.msg)
|
||||
this.pageData()
|
||||
this.dialogVisible = false
|
||||
}
|
||||
})
|
||||
},
|
||||
onDesign(row) {
|
||||
this.designVisible = true
|
||||
this.iframeLoaded()
|
||||
this.designUrl = "/flow/design/designer?id=" + row.id
|
||||
},
|
||||
|
||||
iframeLoaded() {
|
||||
// iframe监听组件内设计器保存事件
|
||||
window.onmessage = (event) => {
|
||||
console.log(event)
|
||||
if (event.data === "success") {
|
||||
this.$message.success("保存成功")
|
||||
this.designVisible = false
|
||||
this.pageData()
|
||||
} else if (event.data === "error") {
|
||||
this.$message.error("保存失败")
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onDeploy(row) {
|
||||
this.$confirm("部署会生成新的流程定义版本,确定部署吗?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(() => {
|
||||
this.$axios.post("/flow/design/deploy", { id: row.id }).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$message.success(res.msg)
|
||||
this.pageData()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
onRedeploy(row) {
|
||||
this.$confirm("重新部署会覆盖最新版流程定义,确定重新部署吗?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(() => {
|
||||
this.$axios.post("/flow/design/redeploy", { id: row.id }).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$message.success(res.msg)
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
onDelete(row) {
|
||||
this.$confirm("您确定要删除吗", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(() => {
|
||||
this.$axios.post("/flow/design/delete", { id: row.id }).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$message.success(res.msg)
|
||||
this.pageData()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
onView(row) {
|
||||
},
|
||||
|
||||
listCategory() {
|
||||
this.$axios.post("/flow/category/list").then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.categoryOptions = res.data
|
||||
}
|
||||
})
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.pageData()
|
||||
this.listCategory()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -0,0 +1,70 @@
|
||||
<!--#
|
||||
layout("/layouts/platform.html"){
|
||||
#-->
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<el-card class="mt10" shadow="never">
|
||||
<el-row type="flex">
|
||||
<el-button @click="openDesigner" size="medium" type="primary">
|
||||
<i class="ti-plus"></i>
|
||||
设计流程
|
||||
</el-button>
|
||||
</el-row>
|
||||
</el-card>
|
||||
|
||||
<el-card class="mt10" shadow="never">
|
||||
<el-table :data="tableData" @sort-change="pageOrder" header-align="center" style="width: 100%">
|
||||
<el-table-column label="模板ID" prop="id"></el-table-column>
|
||||
<el-table-column label="流程模版名称" prop="name"></el-table-column>
|
||||
<el-table-column label="关键字" prop="key"></el-table-column>
|
||||
<el-table-column label="版本" prop="version"></el-table-column>
|
||||
<el-table-column label="创建日期" prop="createDate"></el-table-column>
|
||||
<el-table-column label="操作" width="200px">
|
||||
<template scope="scope">
|
||||
<el-button size="mini" type="primary">查看</el-button>
|
||||
<el-button size="mini" type="danger" @click="doDelete(scope.row.id)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#app",
|
||||
mixins: [initTableMixins],
|
||||
methods: {
|
||||
pageData() {
|
||||
$.get(loc() + "/pageData", this.pageForm).then((res) => {
|
||||
console.log(res)
|
||||
this.tableData = res.data.result
|
||||
this.pageForm.totalCount = res.data.total
|
||||
})
|
||||
},
|
||||
|
||||
doDelete(processId) {
|
||||
this.$confirm("您确定要删除吗?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(() => {
|
||||
$.post(loc() + "/deleteProcess", { processId }).then((res) => {
|
||||
this.$message.success(res.msg)
|
||||
this.doSearch()
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
openDesigner() {
|
||||
window.open("/uflo/designer")
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.pageData()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -0,0 +1,218 @@
|
||||
<!--#
|
||||
layout("/layouts/platform.html"){
|
||||
#-->
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<!-- <iframe src="/uflo/designer"></iframe>-->
|
||||
|
||||
<el-card class="mt10" shadow="never">
|
||||
<el-row type="flex">
|
||||
<el-button @click="openDesigner" size="medium" type="primary">
|
||||
<i class="ti-plus"></i>
|
||||
设计流程
|
||||
</el-button>
|
||||
</el-row>
|
||||
</el-card>
|
||||
|
||||
<el-card class="mt10" shadow="never">
|
||||
<el-table :data="tableData" @sort-change="pageOrder" header-align="center" style="width: 100%">
|
||||
<el-table-column label="主题" prop="subject"></el-table-column>
|
||||
<el-table-column label="标签" prop="tag"></el-table-column>
|
||||
<el-table-column label="流程定义ID" prop="processId"></el-table-column>
|
||||
<el-table-column label="流程实例ID" prop="id"></el-table-column>
|
||||
<el-table-column label="业务ID" prop="businessId"></el-table-column>
|
||||
<el-table-column label="创建日期" prop="createDate"></el-table-column>
|
||||
<el-table-column label="所在节点" prop="currentNode"></el-table-column>
|
||||
<el-table-column label="发起人" prop="promoter"></el-table-column>
|
||||
<el-table-column label="操作" width="200px">
|
||||
<template scope="scope">
|
||||
<el-button size="mini" type="primary" @click="loadTask(scope.row.id)">任务列表</el-button>
|
||||
<el-button size="mini" type="danger" @click="doDeleteProcessInstance(scope.row.id)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
|
||||
<el-dialog title="任务列表" width="1000px" :visible.sync="taskDialog">
|
||||
<el-table :data="taskList" border>
|
||||
<el-table-column label="任务ID" prop="id"></el-table-column>
|
||||
<el-table-column label="任务名称" prop="taskName"></el-table-column>
|
||||
<el-table-column label="节点名称" prop="nodeName"></el-table-column>
|
||||
<el-table-column label="处理人" prop="owner"></el-table-column>
|
||||
<el-table-column label="类型" prop="type"></el-table-column>
|
||||
<el-table-column label="创建日期" prop="createDate"></el-table-column>
|
||||
<el-table-column label="状态" prop="state"></el-table-column>
|
||||
<el-table-column label="操作" width="200">
|
||||
<template scope="scope">
|
||||
<el-link type="primary" @click="openComplete(scope.row.id)">完成任务</el-link>
|
||||
<el-link type="primary">领取任务</el-link>
|
||||
<el-link type="primary" @click="openJump(scope.row.id)">跳转</el-link>
|
||||
<el-link type="primary">流程图</el-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog title="任务跳转" width="600px" :visible.sync="taskJumpDialog" :close-on-click-modal="false">
|
||||
<el-form :model="taskJumpFormData" ref="taskJumpForm" size="small" label-position="top">
|
||||
<el-form-item prop="nodeName" label="跳转目标节点" :rules="[{required:true,message:'请选择',trigger:['change','blur']}]">
|
||||
<el-select v-model="taskJumpFormData.nodeName" style="width: 100%">
|
||||
<el-option v-for="item in taskJumpNodeList" :key="item.name" :label="item.name" :value="item.name"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="taskJumpDialog = false">取 消</el-button>
|
||||
<el-button type="primary" @click="doTaskJump">确 定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog title="完成任务" width="600px" :visible.sync="taskCompleteDialog" :close-on-click-modal="false">
|
||||
<el-form :model="taskCompleteFormData" ref="taskCompleteForm" size="small" label-position="top">
|
||||
<el-form-item prop="variables" label="流程变量">
|
||||
<el-table :data="taskCompleteFormData.variables" border size="mini">
|
||||
<el-table-column label="变量名" prop="key"></el-table-column>
|
||||
<el-table-column label="变量名" prop="value"></el-table-column>
|
||||
<el-table-column label="操作">
|
||||
<template slot="header" scope="scope">
|
||||
<el-button type="primary" size="mini" @click="taskCompleteFormData.variables.push({})">添加变量</el-button>
|
||||
</template>
|
||||
<template slot="header" scope="scope">
|
||||
<el-button type="primary" size="mini" @click="taskCompleteFormData.variables.splice(scope.$index,1)">删除变量</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item prop="sequenceFlowName" label="流转路径" :rules="[{required:true,message:'请选择',trigger:['change','blur']}]">
|
||||
<el-select v-model="taskCompleteFormData.sequenceFlowName" style="width: 100%">
|
||||
<el-option v-for="item in taskSequenceFlows" :key="item.name" :label="item.name" :value="item.value"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="taskCompleteDialog = false">取 消</el-button>
|
||||
<el-button type="primary" @click="doTaskComplete">确 定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#app",
|
||||
mixins: [initTableMixins],
|
||||
data() {
|
||||
return {
|
||||
pageForm: {
|
||||
mode: "running"
|
||||
},
|
||||
taskDialog: false,
|
||||
taskList: [],
|
||||
|
||||
processInstanceId: null,
|
||||
|
||||
taskJumpDialog: false,
|
||||
taskJumpNodeList: [],
|
||||
taskJumpFormData: {
|
||||
taskId: null,
|
||||
nodeName: null
|
||||
},
|
||||
|
||||
taskCompleteDialog: false,
|
||||
taskSequenceFlows: [],
|
||||
taskCompleteFormData: {
|
||||
variables: [],
|
||||
taskId: null,
|
||||
sequenceFlowName: null
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
pageData() {
|
||||
$.get(loc() + "/pageData", this.pageForm).then((res) => {
|
||||
console.log(res)
|
||||
this.tableData = res.data.result
|
||||
this.pageForm.totalCount = res.data.total
|
||||
})
|
||||
},
|
||||
doDeleteProcessInstance(processInstanceId) {
|
||||
this.$confirm("您确定要删除吗?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(() => {
|
||||
$.post(loc() + "/deleteProcessInstance", { processInstanceId }).then((res) => {
|
||||
this.$message.success(res.msg)
|
||||
this.doSearch()
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
loadTask(processInstanceId) {
|
||||
$.get(loc() + "/loadTask", { processInstanceId }).then((res) => {
|
||||
this.taskDialog = true
|
||||
this.taskList = res.data
|
||||
})
|
||||
},
|
||||
|
||||
openComplete(taskId) {
|
||||
this.taskCompleteDialog = true
|
||||
if (this.$refs.taskCompleteForm) {
|
||||
this.$refs.taskCompleteForm.resetFields()
|
||||
}
|
||||
$.get(loc() + "/loadSequenceFlows", { taskId }).then((res) => {
|
||||
this.taskSequenceFlows = res.data
|
||||
this.taskSequenceFlows.unshift({
|
||||
name: "默认",
|
||||
value: null
|
||||
})
|
||||
this.taskCompleteFormData.taskId = taskId
|
||||
})
|
||||
},
|
||||
doTaskComplete() {
|
||||
this.$confirm("真的要完成这个任务吗?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(() => {
|
||||
$.post(loc() + "/completeTask", this.taskCompleteFormData).then((res) => {
|
||||
this.$message.success(res.msg)
|
||||
this.taskCompleteDialog = false
|
||||
this.taskDialog = false
|
||||
this.pageData()
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
openJump(taskId) {
|
||||
this.taskJumpDialog = true
|
||||
if (this.$refs.taskJumpForm) {
|
||||
this.$refs.taskJumpForm.resetFields()
|
||||
}
|
||||
$.get(loc() + "/loadJumpTasks", { taskId }).then((res) => {
|
||||
this.taskJumpNodeList = res.data
|
||||
this.taskJumpFormData.taskId = taskId
|
||||
})
|
||||
},
|
||||
doTaskJump() {
|
||||
$.post(loc() + "/jumpTask", this.taskJumpFormData).then((res) => {
|
||||
this.$message.success(res.msg)
|
||||
this.taskJumpDialog = false
|
||||
this.taskDialog = false
|
||||
this.pageData()
|
||||
})
|
||||
},
|
||||
|
||||
openDesigner() {
|
||||
window.open("/uflo/designer")
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.pageData()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -0,0 +1,489 @@
|
||||
<!--#
|
||||
layout("/layouts/v4/baseLayout.html"){
|
||||
#-->
|
||||
|
||||
<style>
|
||||
.task-todo-center {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
/* 统计卡片样式 */
|
||||
.statistics-section {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
border: none;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.stat-card .el-card__body {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.stat-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.stat-icon {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 20px;
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
.todo-icon {
|
||||
background-color: rgba(64, 158, 255, 0.1);
|
||||
color: #409eff;
|
||||
}
|
||||
|
||||
.done-icon {
|
||||
background-color: rgba(103, 194, 58, 0.1);
|
||||
color: #67c23a;
|
||||
}
|
||||
|
||||
.started-icon {
|
||||
background-color: rgba(230, 162, 60, 0.1);
|
||||
color: #e6a23c;
|
||||
}
|
||||
|
||||
.stat-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 28px;
|
||||
font-weight: 600;
|
||||
line-height: 1.2;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 14px;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
/* 搜索区域样式 */
|
||||
.filter-section {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.filter-section .el-card__body {
|
||||
padding: 15px 20px;
|
||||
}
|
||||
|
||||
.search-form {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.search-form .el-form-item {
|
||||
margin-bottom: 0;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
/* 任务列表区域样式 */
|
||||
.task-section .el-card__header {
|
||||
padding: 0;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
/* 优化后的 tabs 样式 */
|
||||
.task-header .el-tabs__header {
|
||||
margin: 0;
|
||||
padding: 0 20px;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.task-header .el-tabs__nav-wrap::after {
|
||||
height: 1px;
|
||||
background-color: #ebeef5;
|
||||
}
|
||||
|
||||
.task-header .el-tabs__item {
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
font-size: 15px;
|
||||
color: #606266;
|
||||
padding: 0 20px;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.task-header .el-tabs__item.is-active {
|
||||
color: #409eff;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.task-header .el-tabs__active-bar {
|
||||
height: 3px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.task-title {
|
||||
font-weight: 500;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
/* 表格行样式 */
|
||||
.el-table .hover-row {
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
|
||||
/* 优化后的分页样式 */
|
||||
.pagination-container {
|
||||
margin-top: 20px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
.pagination-container .el-pagination {
|
||||
padding: 0;
|
||||
font-weight: normal;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.pagination-container .el-pagination .btn-prev,
|
||||
.pagination-container .el-pagination .btn-next {
|
||||
background-color: #f4f6f8;
|
||||
color: #606266;
|
||||
border-radius: 4px;
|
||||
padding: 0 10px;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
.pagination-container .el-pagination .btn-prev:hover,
|
||||
.pagination-container .el-pagination .btn-next:hover {
|
||||
color: var(--color-primary);
|
||||
background-color: #ecf5ff;
|
||||
}
|
||||
|
||||
.pagination-container .el-pagination .el-pager li {
|
||||
background-color: #f4f6f8;
|
||||
color: #606266;
|
||||
border-radius: 4px;
|
||||
min-width: 32px;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
margin: 0 3px;
|
||||
font-weight: normal;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.pagination-container .el-pagination .el-pager li:hover {
|
||||
color: var(--color-primary);
|
||||
background-color: #ecf5ff;
|
||||
}
|
||||
|
||||
.pagination-container .el-pagination .el-pager li.active {
|
||||
background-color: var(--color-primary);
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.pagination-container .el-pagination .el-pagination__jump {
|
||||
margin-left: 15px;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
.pagination-container .el-pagination .el-pagination__editor.el-input {
|
||||
width: 50px;
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
.pagination-container .el-pagination .el-pagination__editor.el-input .el-input__inner {
|
||||
height: 28px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<div class="task-todo-center">
|
||||
<!-- 统计数据区域 -->
|
||||
<el-row :gutter="20" class="statistics-section">
|
||||
<el-col :span="8">
|
||||
<el-card shadow="hover" class="stat-card">
|
||||
<div class="stat-content">
|
||||
<div class="stat-icon todo-icon">
|
||||
<i class="el-icon-s-claim"></i>
|
||||
</div>
|
||||
<div class="stat-info">
|
||||
<div class="stat-value">{{todoCount}}</div>
|
||||
<div class="stat-label">待办任务</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-card shadow="hover" class="stat-card">
|
||||
<div class="stat-content">
|
||||
<div class="stat-icon done-icon">
|
||||
<i class="el-icon-finished"></i>
|
||||
</div>
|
||||
<div class="stat-info">
|
||||
<div class="stat-value">{{doneCount}}</div>
|
||||
<div class="stat-label">已办任务</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-card shadow="hover" class="stat-card">
|
||||
<div class="stat-content">
|
||||
<div class="stat-icon started-icon">
|
||||
<i class="el-icon-s-promotion"></i>
|
||||
</div>
|
||||
<div class="stat-info">
|
||||
<div class="stat-value">{{startedCount}}</div>
|
||||
<div class="stat-label">我发起的</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 搜索筛选区域 -->
|
||||
<el-card shadow="never" class="filter-section">
|
||||
<el-form :inline="true" :model="pageForm" class="search-form">
|
||||
<el-form-item>
|
||||
<el-input v-model="pageForm.searchKeyword" placeholder="请输入关键词搜索"
|
||||
prefix-icon="el-icon-search"
|
||||
clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-select v-model="pageForm.category" placeholder="所有流程分类" clearable>
|
||||
<el-option v-for="type in categoryOptions" :key="type.id" :label="type.name"
|
||||
:value="type.id"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="search">搜索</el-button>
|
||||
<el-button @click="reset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<!-- 任务列表区域 -->
|
||||
<el-card shadow="never" class="task-section">
|
||||
<div slot="header" class="task-header">
|
||||
<el-tabs v-model="activeTab" @tab-click="handleTabClick">
|
||||
<el-tab-pane label="待办任务" name="todo"></el-tab-pane>
|
||||
<el-tab-pane label="已办任务" name="done"></el-tab-pane>
|
||||
<el-tab-pane label="我发起的" name="started"></el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
|
||||
<!-- 表格展示 -->
|
||||
<el-table v-loading="loading" :data="tasks" style="width: 100%" :key="activeTab"
|
||||
:header-cell-style="{backgroundColor: '#f5f7fa'}">
|
||||
<el-table-column prop="instanceName" label="流程名称" min-width="180" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column prop="taskName" label="任务节点" min-width="150" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column prop="categoryName" label="流程分类" min-width="150" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column prop="initiatorName" label="申请人" min-width="120">
|
||||
<template slot-scope="{row}">{{row.variable.initiatorName}}</template>
|
||||
</el-table-column>
|
||||
<el-table-column v-if="activeTab === 'started'" label="状态" width="100">
|
||||
<template slot-scope="{row}">{{processStatusMap[row.state]?.text}}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="100px" fixed="right">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="primary" size="mini" @click="openView(scope.row)">查看</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 空状态展示 -->
|
||||
<el-empty v-if="tasks.length === 0" :description="getEmptyText()"></el-empty>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="pagination-container" v-if="tasks.length > 0">
|
||||
<el-pagination
|
||||
@current-change="handleCurrentChange"
|
||||
:current-page="pageForm.pageNumber"
|
||||
:page-size="pageForm.pageSize"
|
||||
layout="prev, pager, next, jumper"
|
||||
:total="pageForm.totalCount"
|
||||
></el-pagination>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#app",
|
||||
data() {
|
||||
return {
|
||||
// 统计数据
|
||||
todoCount: 0,
|
||||
doneCount: 0,
|
||||
startedCount: 0,
|
||||
|
||||
// 查询表单
|
||||
pageForm: {
|
||||
pageNumber: 1,
|
||||
pageSize: 10,
|
||||
todoCount: 0,
|
||||
keyword: "",
|
||||
category: ""
|
||||
},
|
||||
|
||||
|
||||
// 流程类型选项
|
||||
categoryOptions: [],
|
||||
|
||||
// 任务列表
|
||||
tasks: [],
|
||||
loading: false,
|
||||
|
||||
// 标签页
|
||||
activeTab: "todo",
|
||||
|
||||
// 当前任务
|
||||
currentTask: null,
|
||||
dialogVisible: false,
|
||||
|
||||
processStatusMap: {
|
||||
10: {text: "进行中", class: "doing"},
|
||||
20: {text: "已完成", class: "finished"},
|
||||
30: {text: "已撤回", class: "withdraw"},
|
||||
40: {text: "强行终止", class: "interrupt"},
|
||||
45: {text: "已拒绝", class: "reject"},
|
||||
50: {text: "挂起", class: "pending"},
|
||||
99: {text: "已废弃", class: "abandon"}
|
||||
},
|
||||
|
||||
// 任务状态枚举
|
||||
taskStateEnum: {
|
||||
DOING: 10,
|
||||
FINISHED: 20,
|
||||
WITHDRAW: 30,
|
||||
INTERRUPT: 40,
|
||||
PENDING: 50,
|
||||
ABANDON: 99
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
if(GetQueryString("status")){
|
||||
this.activeTab = GetQueryString("status")
|
||||
}
|
||||
this.initData()
|
||||
},
|
||||
|
||||
methods: {
|
||||
// 初始化数据
|
||||
async initData() {
|
||||
await Promise.all([this.getStatistics(), this.listCategory(), this.getTasks()])
|
||||
},
|
||||
|
||||
// 获取统计数据
|
||||
async getStatistics() {
|
||||
try {
|
||||
const res = await $.post("/flow/todoCenter/statistics")
|
||||
if (res.code === 0) {
|
||||
const {todoCount, doneCount, startedCount} = res.data
|
||||
this.todoCount = todoCount
|
||||
this.doneCount = doneCount
|
||||
this.startedCount = startedCount
|
||||
}
|
||||
} catch (error) {
|
||||
this.$message.error("获取统计数据失败")
|
||||
console.error("获取统计数据失败:", error)
|
||||
}
|
||||
},
|
||||
|
||||
// 获取流程类型
|
||||
async listCategory() {
|
||||
this.$axios.post("/flow/category/list").then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.categoryOptions = res.data
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 获取任务列表
|
||||
async getTasks() {
|
||||
this.loading = true
|
||||
try {
|
||||
const res = await $.post("/flow/todoCenter/" + this.activeTab, this.pageForm)
|
||||
if (res.code === 0) {
|
||||
this.tasks = res.data.list
|
||||
this.pageForm.totalCount = res.data.totalCount
|
||||
this.dialogVisible = false
|
||||
}
|
||||
} catch (error) {
|
||||
this.$message.error("获取任务列表失败")
|
||||
console.error("获取任务列表失败:", error)
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
|
||||
// 处理标签页点击
|
||||
handleTabClick(tab) {
|
||||
this.activeTab = tab.name
|
||||
this.pageForm.pageNumber = 1
|
||||
this.getTasks()
|
||||
},
|
||||
|
||||
// 搜索
|
||||
search() {
|
||||
this.pageForm.pageNumber = 1
|
||||
this.getTasks()
|
||||
this.getStatistics()
|
||||
},
|
||||
|
||||
// 重置搜索
|
||||
reset() {
|
||||
this.pageForm.searchKeyword = ""
|
||||
this.pageForm.category = ""
|
||||
this.search()
|
||||
},
|
||||
|
||||
// 处理页码变化
|
||||
handleCurrentChange(val) {
|
||||
this.pageForm.pageNumber = val
|
||||
this.getTasks()
|
||||
},
|
||||
|
||||
// 处理任务
|
||||
async openView(task) {
|
||||
console.log(task)
|
||||
const {taskId, taskKey, taskState, instanceId, businessNo, formKey} = task
|
||||
if (!formKey) {
|
||||
this.$message.warning("当前流程没有配置地址")
|
||||
return
|
||||
}
|
||||
window.open(formKey + "?taskId=" + taskId + "bizId=" + businessNo + "taskKey=" + taskKey)
|
||||
},
|
||||
|
||||
// 获取空状态文本
|
||||
getEmptyText() {
|
||||
switch (this.activeTab) {
|
||||
case "todo":
|
||||
return "您当前没有需要办理的任务,辛苦了"
|
||||
case "done":
|
||||
return "您当前没有已办理的任务记录"
|
||||
case "started":
|
||||
return "您当前没有发起的流程"
|
||||
default:
|
||||
return "暂无数据"
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
Reference in New Issue
Block a user