Browse Source

first submit

xiao-xx 1 year ago
parent
commit
6161dff5fe

+ 36 - 0
src/api/activiti/definition.js

@@ -0,0 +1,36 @@
+import request from '@/utils/request'
+
+// 查询流程定义列表
+export function listDefinition(query) {
+  return request({
+    url: '/activiti/definition/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 激活挂起流程定义
+export function suspendOrActiveDefinition(data) {
+  return request({
+    url: '/activiti/definition/suspendOrActiveDefinition',
+    method: 'post',
+    params: data
+  })
+}
+
+// 删除流程定义
+export function delDefinition(deploymentId) {
+  return request({
+    url: '/activiti/definition/remove/' + deploymentId,
+    method: 'delete',
+  })
+}
+
+// 流程定义转成模型
+export function convert2Model(data) {
+  return request({
+    url: '/activiti/definition/convert2Model',
+    method: 'post',
+    params: data
+  })
+}

+ 43 - 0
src/api/activiti/modeler.js

@@ -0,0 +1,43 @@
+import request from '@/utils/request'
+
+// 查询模型列表
+export function listModeler(query) {
+  return request({
+    url: '/activiti/modeler/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 新增模型
+export function addModeler(data) {
+  return request({
+    url: '/activiti/modeler/create',
+    method: 'post',
+    params: data
+  })
+}
+
+// 删除模型
+export function delModeler(modelId) {
+  return request({
+    url: '/activiti/modeler/remove/' + modelId,
+    method: 'delete',
+  })
+}
+
+// 导出模型
+export function exportModeler(modelId) {
+  return request({
+    url: '/activiti/modeler/export/' + modelId,
+    method: 'get',
+  })
+}
+
+// 部署模型
+export function deployModeler(modelId) {
+  return request({
+    url: '/activiti/modeler/deploy/' + modelId,
+    method: 'get',
+  })
+}

+ 435 - 0
src/components/Activiti/ApplyAfter/index.vue

@@ -0,0 +1,435 @@
+<template>
+  <div>
+    <el-button
+      size="mini"
+      type="text"
+      :icon="icon"
+      @click="_handleView"
+    >{{ type === 'todo' ? '办理' : '表单数据' }}</el-button>
+    <el-button
+      size="mini"
+      type="text"
+      icon="el-icon-user"
+      @click="handleViewUserList"
+      v-show="type === 'todo'"
+    >转办</el-button>
+    <el-button
+      size="mini"
+      type="text"
+      icon="el-icon-time"
+      @click="handleViewHistoryList"
+      v-show="row.taskId !== '-2'"
+    >审批历史</el-button>
+    <el-button
+      size="mini"
+      type="text"
+      icon="el-icon-search"
+      @click="handleViewProcessImg"
+      v-show="row.taskId !== '-2'"
+    >进度查看</el-button>
+    <el-button
+      size="mini"
+      type="text"
+      icon="el-icon-back"
+      @click="handleCancel"
+      v-show="row.taskId !== '-1' && row.taskId !== '-2' && type === 'none'"
+    >撤销</el-button>
+    <el-button
+      size="mini"
+      type="text"
+      icon="el-icon-sort"
+      @click="handleState"
+      v-show="row.taskId !== '-1' && row.taskId !== '-2' && type === 'none'"
+    >{{ row.suspendState === '2' ? '激活' : '挂起' }}</el-button>
+
+    <!--业务表单子组件-->
+    <demo-form
+      v-if="row.processKey === 'exampleDemo'"
+      :row="row"
+      :taskId="taskId"
+      :taskName="taskName"
+      :type="type"
+      ref="demoForm"
+    ></demo-form>
+    <leave-form
+      v-if="row.processKey === 'leave'"
+      :row="row"
+      :taskId="taskId"
+      :taskName="taskName"
+      :type="type"
+      ref="leaveForm"
+    ></leave-form>
+
+    <!--进度查看对话框-->
+    <el-dialog title="进度查看" :visible.sync="open" width="1000px" append-to-body>
+      <div style="width: 100%; text-align: center;">
+        <el-image
+          :src="src"
+          :preview-src-list="srcList">
+        </el-image>
+      </div>
+      <div slot="footer" class="dialog-footer" style="text-align: right;">
+        <el-button @click="close">关闭</el-button>
+      </div>
+    </el-dialog>
+
+    <!--审批历史对话框-->
+    <el-dialog title="审批历史" :visible.sync="showHistoryTable" width="1000px" append-to-body>
+      <!--审批历史表格-->
+      <div>
+        <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="70px">
+          <el-form-item label="任务名称" prop="activityName">
+            <el-input
+              v-model="queryParams.activityName"
+              placeholder="请输入任务名称"
+              clearable
+              size="small"
+              @keyup.enter.native="handleQuery"
+            />
+          </el-form-item>
+          <el-form-item label="办理人ID" prop="assignee">
+            <el-input
+              v-model="queryParams.assignee"
+              placeholder="请输入办理人ID"
+              clearable
+              size="small"
+              @keyup.enter.native="handleQuery"
+            />
+          </el-form-item>
+          <el-form-item>
+            <el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+            <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+          </el-form-item>
+        </el-form>
+
+        <el-row :gutter="10" class="mb8">
+          <right-toolbar :showSearch.sync="showSearch" @queryTable="getHistoryList"></right-toolbar>
+        </el-row>
+
+        <el-table v-loading="loading" :data="historyList">
+          <el-table-column v-if="false" label="活动ID" align="center" prop="activityId" width="60" />
+          <el-table-column label="活动名称" align="center" prop="activityName" width="140" />
+          <el-table-column label="办理人ID" align="center" prop="assignee" width="90" />
+          <el-table-column label="办理人" align="center" prop="assigneeName" width="80" />
+          <el-table-column label="审批意见" align="center" prop="comment" />
+          <el-table-column label="开始时间" align="center" prop="startTime" width="160" />
+          <el-table-column label="结束时间" align="center" prop="endTime" width="160" />
+          <el-table-column label="耗时" align="center" prop="durationInMillis" width="150" />
+        </el-table>
+
+        <!--v-show="total>0"-->
+        <pagination
+          v-show="false"
+          :total="total"
+          :page.sync="queryParams.pageNum"
+          :limit.sync="queryParams.pageSize"
+          @pagination="getHistoryList"
+        />
+      </div>
+      <div slot="footer" class="dialog-footer" style="text-align: right;">
+        <el-button @click="showHistoryTable=false">关闭</el-button>
+      </div>
+    </el-dialog>
+
+    <!--用户列表对话框-->
+    <el-dialog title="选择用户" :visible.sync="showUserTable" width="900px" append-to-body>
+      <!--用户列表表格-->
+      <div>
+        <el-form :model="queryUserParams" ref="queryUserForm" :inline="true" v-show="showUserSearch" label-width="68px">
+          <el-form-item label="用户名称" prop="userName">
+            <el-input
+              v-model="queryUserParams.userName"
+              placeholder="请输入用户名称"
+              clearable
+              size="small"
+              style="width: 240px"
+              @keyup.enter.native="handleUserQuery"
+            />
+          </el-form-item>
+          <el-form-item label="手机号码" prop="phonenumber">
+            <el-input
+              v-model="queryUserParams.phonenumber"
+              placeholder="请输入手机号码"
+              clearable
+              size="small"
+              style="width: 240px"
+              @keyup.enter.native="handleUserQuery"
+            />
+          </el-form-item>
+          <el-form-item>
+            <el-button type="cyan" icon="el-icon-search" size="mini" @click="handleUserQuery">搜索</el-button>
+            <el-button icon="el-icon-refresh" size="mini" @click="resetUserQuery">重置</el-button>
+          </el-form-item>
+        </el-form>
+
+        <el-row :gutter="10" class="mb8">
+          <right-toolbar :showSearch.sync="showUserSearch" @queryTable="getUserList"></right-toolbar>
+        </el-row>
+
+        <el-table v-loading="userLoading" :data="userList" @selection-change="handleUserSelectionChange">
+          <el-table-column type="selection" width="50" align="center" />
+          <el-table-column label="用户编号" align="center" prop="userId" />
+          <el-table-column label="用户名称" align="center" prop="userName" :show-overflow-tooltip="true" />
+          <el-table-column label="用户昵称" align="center" prop="nickName" :show-overflow-tooltip="true" />
+          <el-table-column label="部门" align="center" prop="dept.deptName" :show-overflow-tooltip="true" />
+          <el-table-column label="手机号码" align="center" prop="phonenumber" width="120" />
+          <el-table-column label="创建时间" align="center" prop="createTime" width="160">
+            <template slot-scope="scope">
+              <span>{{ parseTime(scope.row.createTime) }}</span>
+            </template>
+          </el-table-column>
+        </el-table>
+
+        <pagination
+          v-show="userTotal>0"
+          :total="userTotal"
+          :page.sync="queryUserParams.pageNum"
+          :limit.sync="queryUserParams.pageSize"
+          @pagination="getUserList"
+        />
+      </div>
+      <div slot="footer" class="dialog-footer" style="text-align: right;">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="showUserTable=false">关闭</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+  import request from '@/utils/request'
+  import { format, formatTotalDateSub } from "@/utils/activiti/myUtil.js"
+  import { listUser } from "@/api/system/user";
+  import DemoForm from "@/views/example/demo/demoForm";
+  import LeaveForm from "@/views/leave/leave/leaveForm";
+
+  export default {
+    name: "ApplyAfter",
+    components: {DemoForm, LeaveForm},
+    props: {
+      /* 表格行数据 */
+      row: {
+        type: Object,
+      },
+      taskId: {
+        type: String,
+      },
+      taskName: {
+        type: String,
+      },
+      type: {
+        type: String,
+        default: 'none',
+      },
+    },
+    data() {
+      return {
+        open: false,
+        src: '',
+        srcList: [],
+
+        showHistoryTable: false,
+        // 遮罩层
+        loading: false,
+        // 查询参数
+        queryParams: {
+          pageNum: 1,
+          pageSize: 999,
+          processInstanceId: null,
+          activityName: null,
+          assignee: null,
+        },
+        // 显示搜索条件
+        showSearch: true,
+        // 总条数
+        total: 0,
+        historyList: [],
+        icon: this.type === 'todo' ? 'el-icon-check' : 'el-icon-document',
+        // 选中行
+        selectedRow: null,
+        // 状态数据字典
+        statusOptions: [],
+        showUserTable: false,
+        // 遮罩层
+        userLoading: false,
+        // 查询参数
+        queryUserParams: {
+          pageNum: 1,
+          pageSize: 10,
+          userName: undefined,
+          phonenumber: undefined,
+          status: undefined,
+        },
+        // 显示搜索条件
+        showUserSearch: true,
+        // 总条数
+        userTotal: 0,
+        userList: [],
+      }
+    },
+    create() {
+      this.getDicts("sys_normal_disable").then(response => {
+        this.statusOptions = response.data;
+      });
+    },
+    methods: {
+      _handleView: function () {
+        switch (this.row.processKey) {
+          case 'exampleDemo':
+            this.$refs.demoForm.form = this.row;
+            this.$refs.demoForm.open = true;
+            break;
+          case 'leave':
+            this.$refs.leaveForm.form = this.row;
+            this.$refs.leaveForm.open = true;
+            break;
+          default:
+            break;
+        }
+      },
+      handleState: function () {
+        const instanceId = this.row.instanceId;
+        const suspendState = this.row.suspendState;
+        const opt = this.row.suspendState === '2' ? '激活': '挂起';
+        this.$confirm('是否确认' + opt + 'ID为"' + instanceId + '"的流程实例?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function () {
+          const data = { "instanceId": instanceId, "suspendState": suspendState };
+          return request({
+            url: '/activiti/process/suspendOrActiveApply',
+            method: 'post',
+            params: data
+          });
+        }).then(response => {
+          this.$emit('getList');
+          this.msgSuccess("操作成功");
+        }).catch(function () {
+        });
+      },
+      handleCancel: function () {
+        const instanceId = this.row.instanceId;
+        this.$confirm('是否确认撤销ID为"' + instanceId + '"的流程实例?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function () {
+          const data = { "instanceId": instanceId };
+          return request({
+            url: '/activiti/process/cancelApply',
+            method: 'post',
+            params: data
+          });
+        }).then(response => {
+          this.$emit('getList');
+          this.msgSuccess("操作成功");
+        }).catch(function () {
+        });
+      },
+      handleViewProcessImg: function() {
+        const baseURL = process.env.VUE_APP_BASE_API;
+        this.src = baseURL + '/activiti/process/read-resource?pProcessInstanceId=' + this.row.instanceId + '&_=' + new Date().getTime();
+        this.srcList = [];
+        this.srcList.push(this.src);
+        this.open = true;
+      },
+      close: function () {
+        this.open = false;
+      },
+      handleViewHistoryList() {
+        this.queryParams.processInstanceId = this.row.instanceId;
+        this.showHistoryTable = true;
+        this.getHistoryList();
+      },
+      getHistoryList: function () {
+        this.loading = true;
+        return request({
+          url: '/activiti/process/listHistory',
+          method: 'post',
+          data: this.queryParams
+        }).then(response => {
+          this.historyList = response.rows;
+          this.historyList.forEach(row => {
+            row.startTime = format(row.startTime, 'yyyy-MM-dd HH:mm:ss');
+            row.endTime = format(row.endTime, 'yyyy-MM-dd HH:mm:ss');
+            row.durationInMillis = formatTotalDateSub(row.durationInMillis / 1000);
+          });
+          this.total = response.total;
+          this.loading = false;
+        }).then(() => {
+        });
+      },
+      /** 搜索按钮操作 */
+      handleQuery() {
+        this.queryParams.pageNum = 1;
+        this.getHistoryList();
+      },
+      /** 重置按钮操作 */
+      resetQuery() {
+        this.resetForm("queryForm");
+        this.handleQuery();
+      },
+      handleViewUserList() {
+        this.showUserTable = true;
+        this.getUserList();
+      },
+      /** 查询用户列表 */
+      getUserList() {
+        this.loading = true;
+        listUser(this.queryUserParams).then(response => {
+            this.userList = response.rows;
+            this.userTotal = response.total;
+            this.userLoading = false;
+          }
+        );
+      },
+      /** 搜索按钮操作 */
+      handleUserQuery() {
+        this.queryUserParams.page = 1;
+        this.getUserList();
+      },
+      /** 重置按钮操作 */
+      resetUserQuery() {
+        this.resetForm("queryUserForm");
+        this.handleUserQuery();
+      },
+      // 多选框选中数据
+      handleUserSelectionChange(selection) {
+        this.selectedRow = selection[0];
+      },
+      /** 提交按钮 */
+      submitForm() {
+        const taskId = this.taskId;
+        const selectedRow = this.selectedRow;
+        if (!selectedRow) {
+          this.msgError('请先选择要转办的用户');
+          return;
+        }
+        if (selectedRow.userName === this.$store.state.user.name) {
+          this.msgError('不能转办给自己');
+          return;
+        }
+        this.$confirm('是否确认转办给' + selectedRow.nickName + '?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return request({
+            url: '/activiti/process/delegate',
+            method: 'post',
+            params: { "taskId": taskId, "delegateToUser": selectedRow.userName },
+          });
+        }).then(() => {
+          this.$emit('getList');
+          this.msgSuccess("操作成功");
+          this.showUserTable = false;
+        })
+      },
+    },
+  }
+</script>
+
+<style scoped>
+
+</style>

+ 74 - 0
src/components/Activiti/ApplyBefore/index.vue

@@ -0,0 +1,74 @@
+<template>
+  <div>
+    <el-button
+      size="mini"
+      type="text"
+      icon="el-icon-check"
+      @click="handleApply"
+    >提交申请</el-button>
+    <el-button
+      size="mini"
+      type="text"
+      icon="el-icon-edit"
+      @click="_handleUpdate"
+    >修改</el-button>
+    <el-button
+      size="mini"
+      type="text"
+      icon="el-icon-delete"
+      @click="_handleDelete"
+    >删除</el-button>
+  </div>
+</template>
+
+<script>
+  import request from '@/utils/request'
+
+  export default {
+    name: "ApplyBefore",
+    props: {
+      /* 表格行数据 */
+      row: {
+        type: Object,
+      },
+      handleUpdate: {
+        type: Function,
+      },
+      handleDelete: {
+        type: Function,
+      },
+      requestMapping: {
+        type: String,
+      },
+    },
+    methods: {
+      handleApply: function () {
+        const id = this.row.id;
+        const requestMapping = this.requestMapping;
+        this.$confirm('是否提交ID为"' + id + '"的申请单据?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return request({
+            url: requestMapping + '/submitApply/' + id,
+            method: 'post',
+          });
+        }).then(() => {
+          this.$emit('getList');
+          this.msgSuccess("申请成功");
+        })
+      },
+      _handleUpdate: function () {
+        this.handleUpdate(this.row);
+      },
+      _handleDelete: function () {
+        this.handleDelete(this.row);
+      },
+    },
+  }
+</script>
+
+<style scoped>
+
+</style>

+ 87 - 0
src/components/Activiti/ViewVerify/index.vue

@@ -0,0 +1,87 @@
+<template>
+  <div>
+    <!--以下是审批字段-->
+    <div v-show="type === 'todo'">
+      <el-form label-width="100px">
+        <el-divider></el-divider>
+        <el-form-item label="审批意见">
+          <el-radio-group v-model="pass">
+            <el-radio label="true">同意</el-radio>
+            <el-radio label="false">驳回</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="批注" prop="remark">
+          <el-input v-model="comment" type="textarea" :value="comment" />
+        </el-form-item>
+      </el-form>
+    </div>
+    <div slot="footer" class="dialog-footer" style="text-align: right;">
+      <el-button v-show="type === 'todo'" type="primary" @click="complete">确 定</el-button>
+      <el-button @click="close">关 闭</el-button>
+    </div>
+  </div>
+</template>
+
+<script>
+  import request from '@/utils/request'
+
+  export default {
+    name: "ViewVerify",
+    props: {
+      row: {
+        type: Object,
+      },
+      taskId: {
+        type: String,
+      },
+      type: {
+        type: String,
+      },
+    },
+    data() {
+      return {
+        pass: 'true',
+        comment: '同意',
+      }
+    },
+    methods: {
+      close: function () {
+        this.$emit('update:open', false);
+      },
+      complete() {
+        this.$parent.$children[0].validate(valid => {
+          if (valid) {
+            const data = {
+              "taskId": this.taskId,
+              "instanceId": this.row.instanceId,
+              "variables": JSON.stringify({
+                "comment": this.comment,
+                "pass": this.pass,
+                "formData": this.row,
+              }),
+            };
+            return request({
+              url: '/activiti/process/complete',
+              method: 'post',
+              params: data
+            }).then(response => {
+              this.close();
+              // 刷新待办事项列表(丑陋的代码 👇)
+              this.$parent.$parent.$parent.$parent.$parent.$parent.getList();
+              this.msgSuccess("操作成功");
+            });
+          }
+        });
+      },
+    },
+    watch: {
+      pass: function(val) {
+        this.comment = val === 'true' ? '同意' : '驳回';
+      },
+    },
+  }
+</script>
+
+<style scoped>
+
+</style>

+ 42 - 0
src/utils/activiti/myUtil.js

@@ -0,0 +1,42 @@
+export function format(time, format) {
+  var t = new Date(time);
+  var tf = function (i) { return (i < 10 ? '0' : '') + i };
+  return format.replace(/yyyy|MM|dd|HH|mm|ss/g, function (a) {
+    switch (a) {
+      case 'yyyy':
+        return tf(t.getFullYear());
+        break;
+      case 'MM':
+        return tf(t.getMonth() + 1);
+        break;
+      case 'mm':
+        return tf(t.getMinutes());
+        break;
+      case 'dd':
+        return tf(t.getDate());
+        break;
+      case 'HH':
+        return tf(t.getHours());
+        break;
+      case 'ss':
+        return tf(t.getSeconds());
+        break;
+    }
+  })
+}
+
+/**
+ * 计算出相差天数
+ * @param secondSub
+ */
+export function formatTotalDateSub (secondSub) {
+  var days = Math.floor(secondSub / (24 * 3600));     // 计算出小时数
+  var leave1 = secondSub % (24*3600) ;                // 计算天数后剩余的毫秒数
+  var hours = Math.floor(leave1 / 3600);              // 计算相差分钟数
+  var leave2 = leave1 % (3600);                       // 计算小时数后剩余的毫秒数
+  var minutes = Math.floor(leave2 / 60);              // 计算相差秒数
+  var leave3 = leave2 % 60;                           // 计算分钟数后剩余的毫秒数
+  var seconds = Math.round(leave3);
+  return days + "天" + hours + "时" + minutes + "分" + seconds + '秒';
+}
+

+ 290 - 0
src/views/activiti/definition/index.vue

@@ -0,0 +1,290 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" v-show="showSearch" :inline="true">
+      <el-form-item label="KEY" prop="key">
+        <el-input
+          v-model="queryParams.key"
+          placeholder="请输入流程KEY"
+          clearable
+          size="small"
+          style="width: 240px"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="名称" prop="name">
+        <el-input
+          v-model="queryParams.name"
+          placeholder="请输入名称"
+          clearable
+          size="small"
+          style="width: 240px"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="所属分类" prop="name">
+        <el-input
+          v-model="queryParams.category"
+          placeholder="请输入所属分类"
+          clearable
+          size="small"
+          style="width: 240px"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          icon="el-icon-upload"
+          size="mini"
+          @click="handleUpload"
+        >部署流程定义</el-button>
+        <span style="color: red; font-size: 12px;">(查看流程图模糊时,可选择 .bpmn 和 .png 一同打成 zip 包部署)</span>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="definitionList">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="流程ID" align="center" prop="id" width="120" />
+      <el-table-column label="流程KEY" align="center" prop="key" width="120" />
+      <el-table-column label="流程名称" align="center" prop="name" width="150" />
+      <el-table-column label="版本" align="center" prop="version" width="90" />
+      <el-table-column label="流程描述" align="center" prop="description" width="150" />
+      <el-table-column label="所属分类" align="center" prop="category" width="120" />
+      <el-table-column label="部署时间" align="center" prop="deploymentTime" width="100" />
+      <!--<el-table-column label="流程定义" align="center" prop="resourceName" width="120">
+        <template slot-scope="scope">
+          <a
+            :href="baseURL + '/activiti/definition/readResource?pdid=' + scope.row.id + '&resourceName=' + scope.row.resourceName "
+            target="_blank"
+            style="color: #409EFF;"
+          >{{ scope.row.resourceName.substring(scope.row.resourceName.lastIndexOf('/') + 1) }}</a>
+        </template>
+      </el-table-column>
+      <el-table-column label="流程图" align="center" prop="diagramResourceName" width="120">
+        <template slot-scope="scope">
+          <img
+            style="width: 100px;"
+            :src="baseURL + '/activiti/definition/readResource?pdid=' + scope.row.id + '&resourceName=' + scope.row.diagramResourceName"
+          />
+        </template>
+      </el-table-column>-->
+      <el-table-column label="状态" align="center" prop="suspendStateName" width="90" />
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-sort"
+            @click="handleState(scope.row)"
+          >{{ scope.row.suspendState === '2' ? '激活' : '挂起' }}</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-refresh"
+            @click="handleConvert(scope.row)"
+          >转模型</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+          >删除</el-button>
+        </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 v-bind="$attrs" v-on="$listeners" @open="onOpen" @close="onClose" :title="title" :visible.sync="open" width="500px" append-to-body>
+      <el-form ref="elForm" :model="formData" :rules="rules" size="medium" label-width="100px">
+        <el-form-item label="上传" prop="upload" required>
+          <el-upload ref="upload" :file-list="uploadfileList" :action="uploadAction"
+                     :before-upload="uploadBeforeUpload">
+            <el-button size="small" type="primary" icon="el-icon-upload">点击上传</el-button>
+          </el-upload>
+        </el-form-item>
+      </el-form>
+      <div slot="footer">
+        <el-button @click="close">取消</el-button>
+        <el-button type="primary" @click="handelConfirm">确定</el-button>
+      </div>
+    </el-dialog>
+
+  </div>
+</template>
+
+<script>
+  import { listDefinition, delDefinition, suspendOrActiveDefinition, convert2Model } from "@/api/activiti/definition.js"
+  import { format } from "@/utils/activiti/myUtil.js"
+
+  export default {
+    name: "Definition",
+    data() {
+      return {
+        // 遮罩层
+        loading: true,
+        // 选中数组
+        ids: [],
+        // 显示搜索条件
+        showSearch: true,
+        // 总条数
+        total: 0,
+        // 流程定义表格数据
+        definitionList: [],
+        // 弹出层标题
+        title: "",
+        // 是否显示弹出层
+        open: false,
+        // 日期范围
+        dateRange: [],
+        // 查询参数
+        queryParams: {
+          pageNum: 1,
+          pageSize: 10,
+          key: undefined,
+          name: undefined,
+          category: undefined,
+        },
+        // 表单参数
+        form: {},
+        rules: {},
+        formData: {
+          upload: null,
+        },
+        uploadAction: process.env.VUE_APP_BASE_API + '/activiti/definition/upload',
+        uploadfileList: [],
+        baseURL: process.env.VUE_APP_BASE_API,
+      };
+    },
+    created() {
+      this.getList();
+    },
+    methods: {
+      /** 查询流程定义列表 */
+      getList() {
+        this.loading = true;
+        listDefinition(this.queryParams).then(
+          response => {
+            this.definitionList = response.rows;
+            this.definitionList.forEach(row => {
+              row.deploymentTime = format(row.deploymentTime, 'yyyy-MM-dd HH:mm:ss');
+            });
+            this.total = response.total;
+            this.loading = false;
+          }
+        );
+      },
+      /** 搜索按钮操作 */
+      handleQuery() {
+        this.queryParams.pageNum = 1;
+        this.getList();
+      },
+      /** 重置按钮操作 */
+      resetQuery() {
+        this.dateRange = [];
+        this.resetForm("queryForm");
+        this.handleQuery();
+      },
+      /** 新增按钮操作 */
+      handleUpload() {
+        this.open = true;
+        this.title = "部署流程定义";
+      },
+      onOpen() {},
+      onClose() {
+        this.$refs['elForm'].resetFields()
+      },
+      close() {
+        this.open = false;
+        this.formData = {
+          upload: null,
+        };
+        this.uploadfileList = [];
+      },
+      handelConfirm() {
+        // this.$refs['elForm'].validate(valid => {
+        //   if (!valid) return;
+        //   this.close()
+        // })
+        this.$refs.upload.submit();
+        this.close();
+        this.getList();
+      },
+      uploadBeforeUpload(file) {
+        let isRightSize = file.size / 1024 / 1024 < 2
+        if (!isRightSize) {
+          this.$message.error('文件大小超过 2MB')
+        }
+        return isRightSize
+      },
+      /** 激活挂起按钮操作 */
+      handleState(row) {
+        const pid = row.id;
+        const suspendState = row.suspendState;
+        const opt = row.suspendState === '2' ? '激活': '挂起';
+        this.$confirm('是否确认' + opt + 'ID为"' + pid + '"的流程定义?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function () {
+          const data = { "id": pid, "suspendState": suspendState };
+          return suspendOrActiveDefinition(data);
+        }).then(response => {
+          this.msgSuccess("操作成功");
+          this.getList();
+        }).catch(function () {
+        });
+      },
+      /** 转模型按钮操作 */
+      handleConvert(row) {
+        const pid = row.id;
+        this.$confirm('是否确认将ID为"' + pid + '"的流程定义转换成流程模型?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function () {
+          const data = { "processDefinitionId": pid };
+          return convert2Model(data);
+        }).then(response => {
+          this.msgSuccess("操作成功");
+          this.getList();
+        }).catch(function () {
+        });
+      },
+      /** 删除按钮操作 */
+      handleDelete(row) {
+        const deploymentId = row.deploymentId;
+        this.$confirm('是否确认删除ID为"' + deploymentId + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function () {
+          return delDefinition(deploymentId);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(function () {
+        });
+      },
+    },
+  }
+</script>
+
+<style scoped>
+
+</style>

+ 302 - 0
src/views/activiti/modeler/index.vue

@@ -0,0 +1,302 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" v-show="showSearch" :inline="true">
+      <el-form-item label="KEY" prop="key">
+        <el-input
+          v-model="queryParams.key"
+          placeholder="请输入KEY"
+          clearable
+          size="small"
+          style="width: 240px"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="名称" prop="name">
+        <el-input
+          v-model="queryParams.name"
+          placeholder="请输入名称"
+          clearable
+          size="small"
+          style="width: 240px"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['activiti:modeler:add']"
+        >创建新模型</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="modelerList">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="ID" align="center" prop="id" width="120" />
+      <el-table-column label="KEY" align="center" prop="key" width="120" />
+      <el-table-column label="名称" align="center" prop="name" width="150" />
+      <el-table-column label="版本" align="center" prop="version" width="150" />
+      <el-table-column label="创建时间" align="center" prop="createTime" width="180" />
+      <el-table-column label="最后更新时间" align="center" prop="lastUpdateTime" width="180" />
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['activiti:modeler:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-upload2"
+            @click="handleDeploy(scope.row)"
+            v-hasPermi="['activiti:modeler:deploy']"
+          >部署</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-download"
+            @click="handleExport(scope.row)"
+            v-hasPermi="['activiti:modeler:export']"
+          >导出</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['activiti:modeler:remove']"
+          >删除</el-button>
+        </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" :visible.sync="open" width="500px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="KEY" prop="key">
+          <el-input v-model="form.key" placeholder="请输入KEY" />
+        </el-form-item>
+        <el-form-item label="名称" prop="name">
+          <el-input v-model="form.name" placeholder="请输入名称" />
+        </el-form-item>
+        <el-form-item label="描述" prop="description">
+          <el-input v-model="form.description" type="textarea" placeholder="请输入描述" />
+        </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>
+
+  </div>
+</template>
+
+<script>
+  import { listModeler, delModeler, addModeler, deployModeler, exportModeler } from "@/api/activiti/modeler.js"
+  import { format } from "@/utils/activiti/myUtil.js"
+
+  export default {
+    name: "Modeler",
+    data() {
+      return {
+        // 遮罩层
+        loading: true,
+        // 选中数组
+        ids: [],
+        // 显示搜索条件
+        showSearch: true,
+        // 总条数
+        total: 0,
+        // 模型表格数据
+        modelerList: [],
+        // 弹出层标题
+        title: "",
+        // 是否显示弹出层
+        open: false,
+        // 日期范围
+        dateRange: [],
+        // 查询参数
+        queryParams: {
+          pageNum: 1,
+          pageSize: 10,
+          key: undefined,
+          name: undefined,
+        },
+        // 表单参数
+        form: {},
+        defaultProps: {
+          children: "children",
+          label: "label"
+        },
+        // 表单校验
+        rules: {
+          key: [
+            { required: true, message: "KEY不能为空", trigger: "blur" }
+          ],
+          name: [
+            { required: true, message: "名称不能为空", trigger: "blur" }
+          ],
+        }
+      };
+    },
+    created() {
+      this.getList();
+    },
+    methods: {
+      /** 查询模型列表 */
+      getList() {
+        this.loading = true;
+        listModeler(this.queryParams).then(
+          response => {
+            this.modelerList = response.rows;
+            this.modelerList.forEach(row => {
+              row.createTime = format(row.createTime, 'yyyy-MM-dd HH:mm:ss');
+              row.lastUpdateTime = format(row.lastUpdateTime, 'yyyy-MM-dd HH:mm:ss');
+            });
+            this.total = response.total;
+            this.loading = false;
+          }
+        );
+      },
+      // 取消按钮
+      cancel() {
+        this.open = false;
+        this.reset();
+      },
+      // 表单重置
+      reset() {
+        this.form = {
+          id: undefined,
+          name: undefined,
+          key: undefined,
+          description: undefined,
+        };
+        this.resetForm("form");
+      },
+      /** 搜索按钮操作 */
+      handleQuery() {
+        this.queryParams.pageNum = 1;
+        this.getList();
+      },
+      /** 重置按钮操作 */
+      resetQuery() {
+        this.dateRange = [];
+        this.resetForm("queryForm");
+        this.handleQuery();
+      },
+      /** 新增按钮操作 */
+      handleAdd() {
+        this.reset();
+        this.open = true;
+        this.title = "添加模型";
+      },
+      /** 修改按钮操作 */
+      handleUpdate(row) {
+        this.reset();
+        const modelId = row.id;
+        this.designModeler(modelId);
+      },
+      /** 提交按钮 */
+      submitForm: function () {
+        this.$refs["form"].validate(valid => {
+          if (valid) {
+            addModeler(this.form).then(response => {
+              if (response.code === 200) {
+                this.msgSuccess("新增成功");
+                this.open = false;
+                this.getList();
+
+                this.designModeler(response.data)
+              }
+            });
+          }
+        });
+      },
+      /** 模型在线设计 */
+      designModeler(id) {
+        // 打开新标签页
+        const routeUrl = this.$router.resolve({
+          path: process.env.VUE_APP_BASE_API + "/modeler/modeler.html?modelId=" + id,
+        });
+        window.open(routeUrl.href, '_blank');
+      },
+      /** 删除按钮操作 */
+      handleDelete(row) {
+        const modelIds = row.id;
+        this.$confirm('是否确认删除ID为"' + modelIds + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function () {
+          return delModeler(modelIds);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(function () {
+        });
+      },
+      /** 导出按钮操作 */
+      handleExport(row) {
+        const modelId = row.id;
+        this.$confirm('是否确认导出ID为"' + modelId + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function () {
+          return exportModeler(modelId);
+        }).then(response => {
+          //创建一个隐藏的a连接,
+          const link = document.createElement('a');
+          let blob = new Blob([response]/*, {type: 'application/xml'}*/);
+          link.style.display = 'none';
+          //设置连接
+          link.href = URL.createObjectURL(blob);
+          link.download = '导出_' + new Date().getTime() + '.bpmn';
+          document.body.appendChild(link);
+          //模拟点击事件
+          link.click();
+        }).catch(function () {
+        });
+      },
+      /** 部署按钮操作 */
+      handleDeploy(row) {
+        const modelId = row.id;
+        this.$confirm('是否确认部署ID为"' + modelId + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function () {
+          return deployModeler(modelId);
+        }).then(response => {
+          this.msgSuccess("部署成功");
+        }).catch(function () {
+        });
+      },
+    },
+  }
+</script>
+
+<style scoped>
+
+</style>