Files
2022-12-21 14:50:22 +08:00

863 lines
23 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="app-container">
<el-form
:model="queryParams"
ref="queryFormRef"
:inline="true"
v-show="showSearch"
label-width="68px"
>
<el-form-item label="模型标识" prop="modelKey">
<el-input
v-model="queryParams.modelKey"
placeholder="请输入模型标识"
clearable
size="small"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="模型名称" prop="modelName">
<el-input
v-model="queryParams.modelName"
placeholder="请输入模型名称"
clearable
size="small"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="流程分类" prop="category">
<el-select
v-model="queryParams.category"
clearable
placeholder="请选择"
size="small"
>
<el-option
v-for="item in categoryOptions"
:key="item.categoryId"
:label="item.categoryName"
:value="item.code"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button
type="primary"
icon="search"
size="small"
@click="handleQuery"
>搜索</el-button
>
<el-button icon="refresh" size="small" @click="resetQuery"
>重置</el-button
>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<!-- <el-col :span="1.5">-->
<!-- <el-button-->
<!-- type="primary"-->
<!-- plain-->
<!-- icon="upload"-->
<!-- size="small"-->
<!-- @click="handleImport"-->
<!-- v-hasPermi="['flowable:model:import']"-->
<!-- >导入</el-button>-->
<!-- </el-col>-->
<el-col :span="1.5">
<el-button
type="success"
plain
icon="plus"
size="small"
@click="handleAdd"
v-hasPermi="['flowable:model:add']"
>新增</el-button
>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="delete"
size="small"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['flowable:model:remove']"
>删除</el-button
>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="download"
size="small"
@click="handleExport"
v-hasPermi="['flowable:model:export']"
>导出</el-button
>
</el-col>
<right-toolbar
:showSearch.sync="showSearch"
@queryTable="getList"
></right-toolbar>
</el-row>
<el-table
v-loading="loading"
fit
:data="modelList"
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" width="55" align="center" />
<el-table-column
label="模型标识"
align="center"
prop="modelKey"
:show-overflow-tooltip="true"
/>
<el-table-column
label="模型名称"
align="center"
:show-overflow-tooltip="true"
>
<template #default="{ row }">
<el-button type="primary" link @click="handleProcessView(row)">
<span>{{ row.modelName }}</span>
</el-button>
</template>
</el-table-column>
<el-table-column
label="流程分类"
align="center"
prop="categoryName"
:formatter="categoryFormat"
/>
<el-table-column label="模型版本" align="center">
<template #default="{ row }">
<el-tag size="default">v{{ row.version }}</el-tag>
</template>
</el-table-column>
<el-table-column
label="描述"
align="center"
prop="description"
:show-overflow-tooltip="true"
/>
<el-table-column
label="创建时间"
align="center"
prop="createTime"
width="180"
/>
<el-table-column
label="操作"
align="center"
class-name="small-padding fixed-width"
>
<template #default="{ row }">
<div class="model-operation">
<el-button
size="small"
link
type="primary"
icon="edit"
@click="handleUpdate(row)"
v-hasPermi="['flowable:model:edit']"
>修改</el-button
>
<el-button
link
type="primary"
size="small"
icon="brush"
@click="handleDesigner(row)"
v-hasPermi="['flowable:model:designer']"
>设计</el-button
>
<el-button
link
type="primary"
size="small"
icon="video-play"
v-hasPermi="['flowable:model:deploy']"
@click.native="handleDeploy(row)"
>部署</el-button
>
<el-dropdown>
<span class="el-dropdown-link">
<el-icon>
<ArrowDown />
</el-icon>
更多
</span>
<template #dropdown>
<el-dropdown-menu>
<!-- TODO: v-hasPermi="['flowable:model:query']" -->
<el-dropdown-item
icon="view"
@click.native="handleProcessView(row)"
>流程图</el-dropdown-item
>
<!-- TODO: v-hasPermi="['flowable:model:list']" -->
<el-dropdown-item
icon="price-tag"
@click.native="handleHistory(row)"
>历史</el-dropdown-item
>
<!-- TODO: v-hasPermi="['flowable:model:remove']" -->
<el-dropdown-item
icon="delete"
@click.native="handleDelete(row)"
>删除</el-dropdown-item
>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total > 0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
<!-- 添加或修改模型信息对话框 -->
<el-dialog
:title="title"
v-model="open"
width="30%"
append-to-body
@close="cancel()"
>
<el-form
ref="formRef"
:model="formData"
:rules="rules"
label-width="80px"
>
<el-form-item label="模型标识" prop="modelKey">
<el-input v-model="formData.modelKey" clearable disabled />
</el-form-item>
<el-form-item label="模型名称" prop="modelName">
<el-input
v-model="formData.modelName"
clearable
:disabled="formData.modelId !== undefined"
/>
</el-form-item>
<el-form-item label="流程分类" prop="category">
<el-select
v-model="formData.category"
placeholder="请选择"
clearable
style="width: 100%"
>
<el-option
v-for="item in categoryOptions"
:key="item.categoryId"
:label="item.categoryName"
:value="item.code"
/>
</el-select>
</el-form-item>
<el-form-item label="描述" prop="description">
<el-input
v-model="formData.description"
type="textarea"
placeholder="请输入内容"
maxlength="200"
show-word-limit
/>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel()"> </el-button>
</div>
</el-dialog>
<!-- &lt;!&ndash; bpmn20.xml导入对话框 &ndash;&gt;-->
<!-- <el-dialog :title="upload.title" :visible.sync="upload.open" width="400px" append-to-body @close="cancel('uploadForm')">-->
<!-- <el-upload-->
<!-- ref="upload"-->
<!-- :limit="1"-->
<!-- accept=".xml"-->
<!-- :headers="upload.headers"-->
<!-- :action="upload.url + '?name=' + upload.name+'&category='+ upload.category"-->
<!-- :disabled="upload.isUploading"-->
<!-- :on-progress="handleFileUploadProgress"-->
<!-- :on-success="handleFileSuccess"-->
<!-- :auto-upload="false"-->
<!-- drag-->
<!-- >-->
<!-- <i class="el-icon-upload"></i>-->
<!-- <div class="el-upload__text">-->
<!-- 将文件拖到此处-->
<!-- <em>点击上传</em>-->
<!-- </div>-->
<!-- <div class="el-upload__tip" slot="tip">-->
<!-- <el-form ref="uploadForm" :model="upload" size="small" :rules="rules" label-width="80px">-->
<!-- <el-form-item label="流程名称" prop="name">-->
<!-- <el-input v-model="upload.name" clearable/>-->
<!-- </el-form-item>-->
<!-- <el-form-item label="流程分类" prop="category">-->
<!-- <el-select v-model="upload.category" placeholder="请选择" clearable style="width:100%">-->
<!-- <el-option v-for="item in categoryOptions" :key="item.categoryId" :label="item.categoryName"-->
<!-- :value="item.code"/>-->
<!-- </el-select>-->
<!-- </el-form-item>-->
<!-- </el-form>-->
<!-- </div>-->
<!-- <div class="el-upload__tip" style="color:red" slot="tip">提示仅允许导入bpmn20.xml格式文件</div>-->
<!-- </el-upload>-->
<!-- <div slot="footer" class="dialog-footer">-->
<!-- <el-button type="primary" @click="submitFileForm"> </el-button>-->
<!-- <el-button @click="cancel('uploadForm')"> </el-button>-->
<!-- </div>-->
<!-- </el-dialog>-->
<!-- 流程图 -->
<el-dialog
:title="processView.title"
v-model="processView.open"
width="70%"
append-to-body
>
<process-viewer
:key="`designer-${processView.index}`"
:xml="processView.xmlData"
:style="{ height: '400px' }"
/>
</el-dialog>
<el-dialog title="模型历史" v-model="history.open" width="70%">
<el-table
v-loading="history.loading"
fit
:data="historyList"
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" width="55" align="center" />
<el-table-column
label="模型标识"
align="center"
prop="modelKey"
:show-overflow-tooltip="true"
/>
<el-table-column
label="模型名称"
align="center"
:show-overflow-tooltip="true"
>
<template #default="{ row }">
<el-button link @click="handleProcessView(row)">
<span>{{ row.modelName }}</span>
</el-button>
</template>
</el-table-column>
<el-table-column
label="流程分类"
align="center"
prop="categoryName"
:formatter="categoryFormat"
/>
<el-table-column label="模型版本" align="center">
<template #default="{ row }">
<el-tag size="default">v{{ row.version }}</el-tag>
</template>
</el-table-column>
<el-table-column
label="描述"
align="center"
prop="description"
:show-overflow-tooltip="true"
/>
<el-table-column
label="创建时间"
align="center"
prop="createTime"
width="180"
/>
<el-table-column
label="操作"
align="center"
class-name="small-padding fixed-width"
>
<template #default="{ row }">
<el-button
link
size="small"
icon="video-play"
v-hasPermi="['flowable:model:deploy']"
@click.native="handleDeploy(row)"
>部署</el-button
>
<el-button
link
size="small"
icon="star-off"
v-hasPermi="['flowable:model:save']"
@click.native="handleLatest(row)"
>设为最新</el-button
>
</template>
</el-table-column>
</el-table>
<pagination
v-show="historyTotal > 0"
:total="historyTotal"
v-model:page="queryHistoryParams.pageNum"
v-model:limit="queryHistoryParams.pageSize"
@pagination="getHistoryList"
/>
</el-dialog>
<el-dialog
:title="designerData.title"
v-model="designerOpen"
append-to-body
fullscreen
>
<process-designer
:key="designerOpen"
style="border: 1px solid rgba(0, 0, 0, 0.1)"
ref="modelDesigner"
v-loading="designerData.loading"
:bpmnXml="designerData.bpmnXml"
:designerForm="designerData.form"
@save="onSaveDesigner"
/>
</el-dialog>
</div>
</template>
<script setup>
import {
getBpmnXml,
listModel,
historyModel,
latestModel,
addModel,
updateModel,
saveModel,
delModel,
deployModel,
} from "@/api/flowable/model";
import { listAllCategory } from "@/api/flowable/category";
import { ArrowDown } from "@element-plus/icons-vue";
import ProcessDesigner from "@/components/ProcessDesigner";
import ProcessViewer from "@/components/ProcessViewer";
import { getToken } from "@/utils/auth";
import { toRefs } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
let bpmnXml;
// 显示搜索条件
const showSearch = ref(true);
// 遮罩层
const loading = ref(true);
// 选中数组
const ids = ref([]);
// 非单个禁用
const single = ref(true);
// 非多个禁用
const multiple = ref(true);
// 总条数
const total = ref(0);
// 流程模型表格数据
const modelList = ref([]);
const categoryOptions = ref([]);
const title = ref("");
const open = ref(false);
const designerOpen = ref(false);
const designerModelId = ref(null);
const currentRow = ref(null);
const historyList = ref([]);
const historyTotal = ref(0);
const formRef = ref();
const data = reactive({
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
modelKey: null,
modelName: null,
category: null,
},
formData: {},
// 表单校验
rules: {
modelKey: [
{ required: true, message: "模型标识不能为空", trigger: "blur" },
],
modelName: [
{ required: true, message: "模型名称不能为空", trigger: "blur" },
],
category: [{ required: true, message: "请选择类型", trigger: "change" }],
},
processView: {
title: "",
open: false,
index: undefined,
xmlData: "",
},
// bpmn.xml 导入
upload: {
// 是否显示弹出层xml导入
open: false,
// 弹出层标题xml导入
title: "",
// 是否禁用上传
isUploading: false,
name: null,
category: null,
// 设置上传的请求头部
headers: { Authorization: "Bearer " + getToken() },
// 上传的地址
url: import.meta.env.VUE_APP_BASE_API + "/workflow/definition/import",
},
designerData: {
loading: false,
bpmnXml: "",
modelId: null,
form: {
processName: null,
processKey: null,
},
},
history: {
open: false,
loading: false,
},
queryHistoryParams: {
pageNum: 1,
pageSize: 10,
modelKey: null,
},
});
const {
formData,
rules,
queryParams,
processView,
upload,
designerData,
history,
queryHistoryParams,
} = toRefs(data);
/** 查询流程分类列表 */
function getCategoryList() {
listAllCategory().then((response) => (categoryOptions.value = response.rows));
}
/** 查询流程模型列表 */
function getList() {
loading.value = true;
listModel(queryParams.value).then((response) => {
modelList.value = response.rows;
total.value = response.total;
loading.value = false;
});
}
function cancel() {
this.reset();
// 关闭dialog
this.open = false;
}
// 表单重置
function reset() {
formData.value = {
modelId: undefined,
modelKey: undefined,
modelName: undefined,
category: undefined,
description: undefined,
};
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
const queryFormRef = ref();
function resetQuery() {
queryFormRef.value.resetFields();
handleQuery();
}
// 多选框选中数据
function handleSelectionChange(selection) {
ids.value = selection.map((item) => item.modelId);
single.value = selection.length !== 1;
multiple.value = !selection.length;
}
/** 部署流程 */
function handleDeploy(row) {
loading.value = true;
deployModel({
modelId: row.modelId,
})
.then((response) => {
ElMessage.success(response.msg);
let obj = { name: "Deploy", path: "/workflow/deploy" };
// return this.$store
// .dispatch("tagsView/delCachedView", obj)
// .then(() => {
// this.$router.push(obj);
// });
})
.finally(() => {
loading.value = false;
});
}
/** 查看流程图 */
function handleProcessView(row) {
let modelId = row.modelId;
processView.value.title = "流程图";
processView.value.index = modelId;
// 发送请求获取xml
getBpmnXml(modelId).then((response) => {
processView.value.xmlData = response.data;
});
processView.value.open = true;
}
function getHistoryList() {
history.value.loading = true;
historyModel(queryHistoryParams.value).then((response) => {
historyTotal.value = response.total;
historyList.value = response.rows;
history.value.loading = false;
});
}
function handleHistory(row) {
history.value.open = true;
queryHistoryParams.value.modelKey = row.modelKey;
getHistoryList();
}
/** 设为最新版 */
function handleLatest(row) {
ElMessageBox.confirm("是否确认将此版本设为最新?").then(() => {
this.history.loading = true;
latestModel({
modelId: row.modelId,
})
.then((response) => {
this.history.open = false;
this.getList();
ElMessage.success(response.msg);
})
.finally(() => {
this.history.loading = false;
});
});
}
function handleCurrentChange(data) {
if (data) {
this.currentRow = JSON.parse(data.content);
}
}
function handleAdd() {
title.value = "新增流程模型";
const dateTime = new Date().getTime();
formData.value = {
modelKey: `Process_${dateTime}`,
modelName: `业务流程_${dateTime}`,
};
open.value = true;
}
/** 修改按钮操作 */
function handleUpdate(row) {
this.title = "修改流程模型";
formData.value = {
modelId: row.modelId,
modelKey: row.modelKey,
modelName: row.modelName,
category: row.category,
description: row.description,
};
this.open = true;
}
function submitForm() {
formRef.value.validate((valid) => {
if (valid) {
if (formData.value.modelId !== undefined) {
updateModel(formData.value).then((response) => {
ElMessage.success("修改成功");
open.value = false;
getList();
});
} else {
addModel(formData.value).then((response) => {
ElMessage.success("新增成功");
open.value = false;
getList();
});
}
}
});
}
/** 设计按钮操作 */
function handleDesigner(row) {
designerData.value.title = "流程设计 - " + row.modelName;
designerData.value.modelId = row.modelId;
designerData.value.form = {
processName: row.modelName,
processKey: row.modelKey,
};
if (row.modelId) {
designerData.value.loading = true;
getBpmnXml(row.modelId).then((response) => {
designerData.value.bpmnXml = response.data || "";
designerData.value.loading = false;
designerOpen.value = true;
});
}
}
function onSaveDesigner(bpmnXmlArgv) {
// bpmnXml = bpmnXmlArgv;
let dataBody = {
modelId: designerData.value.modelId,
bpmnXml: bpmnXmlArgv,
};
ElMessageBox.confirm("是否将此模型保存为新版本?", "提示", {
distinguishCancelAndClose: true,
confirmButtonText: "是",
cancelButtonText: "否",
})
.then(() => {
confirmSave(dataBody, true);
})
.catch((action) => {
if (action === "cancel") {
confirmSave(dataBody, false);
}
});
}
function confirmSave(body, newVersion) {
designerData.value.loading = true;
saveModel(
Object.assign(body, {
newVersion: newVersion,
})
)
.then((res) => {
ElMessage.success(res.msg);
designerOpen.value = false;
getList();
})
.catch((res) => {
ElMessage.error(res.msg);
designerData.value.loading = false;
});
}
/** 删除按钮操作 */
function handleDelete(row) {
const modelIds = row.modelId || ids.value;
ElMessageBox.confirm('是否确认删除模型编号为"' + modelIds + '"的数据项?')
.then(() => {
loading.value = true;
return delModel(modelIds);
})
.then(() => {
loading.value = false;
getList();
ElMessage.success("删除成功");
})
.finally(() => {
loading.value = false;
});
}
/** 导出按钮操作 */
function handleExport() {
this.download(
"workflow/model/export",
{
...this.queryParams,
},
`wf_model_${new Date().getTime()}.xlsx`
);
}
/** 导入bpmn.xml文件 */
function handleImport() {
this.upload.title = "bpmn20.xml文件导入";
this.upload.open = true;
}
// 文件上传中处理
function handleFileUploadProgress(event, file, fileList) {
this.upload.isUploading = true;
}
// 文件上传成功处理
function handleFileSuccess(response, file, fileList) {
this.upload.open = false;
this.upload.isUploading = false;
this.$refs.upload.clearFiles();
this.$message.success(response.msg);
this.getList();
}
// 提交上传文件
function submitFileForm() {
this.$refs.uploadForm.validate((valid) => {
if (valid) {
this.$refs.upload.submit();
}
});
}
function categoryFormat(row, column) {
return (
categoryOptions.value.find((k) => k.code === row.category)?.categoryName ??
""
);
}
function submitSave() {
getList();
}
getList();
getCategoryList();
</script>
<style scoped>
.model-operation {
display: flex;
flex-wrap: wrap;
align-items: center;
}
</style>
<!--
<script>
export default {
name: "Model",
components: {
ProcessDesigner,
ProcessViewer,
},
data() {
return {
};
},
created() {
this.getCategoryList();
this.getList();
},
methods: {
},
};
</script>
-->