490 lines
15 KiB
HTML
490 lines
15 KiB
HTML
<!--#
|
|
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>
|
|
|
|
<!--#
|
|
}
|
|
#-->
|