361 lines
14 KiB
HTML
361 lines
14 KiB
HTML
<!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="/assets/platform/plugins/logicflow/index.min.js"></script>
|
||
<!-- <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-if="approvalInfo.taskState === 10">
|
||
{{ approvalInfo.taskActorList.map(u => u.actorName + '(' + u.actorAccount + ')').join('、') }}
|
||
</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" v-if="approvalInfo.taskState !== 10">
|
||
{{getSubmitTypeText(approvalInfo.ext.submitType)}}
|
||
</span>
|
||
<span class="info-value" v-else>
|
||
暂未处理
|
||
</span>
|
||
</div>
|
||
<div class="info-row">
|
||
<span class="info-label">提交意见:</span>
|
||
<span class="info-value" v-if="approvalInfo.taskState !== 10">{{approvalInfo.taskFormData.opinion}}</span>
|
||
<span class="info-value" v-else>暂未处理</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>
|
||
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 && [10, 20].includes(item.taskState))
|
||
|
||
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>
|