瀏覽代碼

新增示例,请假流程

xiao-xx 1 年之前
父節點
當前提交
e70912c142

+ 3 - 3
.env.staging

@@ -1,11 +1,11 @@
 # 页面标题
-VITE_APP_TITLE = 若依管理系统
+VITE_APP_TITLE = 亿网管理系统
 
 # 生产环境配置
 VITE_APP_ENV = 'staging'
 
-# 若依管理系统/生产环境
+# 亿网管理系统/生产环境
 VITE_APP_BASE_API = '/stage-api'
 
 # 是否在打包时开启压缩,支持 gzip 和 brotli
-VITE_BUILD_COMPRESS = gzip
+VITE_BUILD_COMPRESS = gzip

+ 2 - 2
index.html

@@ -7,7 +7,7 @@
   <meta name="renderer" content="webkit">
   <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
   <link rel="icon" href="/favicon.ico">
-  <title>若依管理系统</title>
+  <title>亿网管理系统</title>
   <!--[if lt IE 11]><script>window.location.href='/html/ie.html';</script><![endif]-->
   <style>
     html,
@@ -212,4 +212,4 @@
   <script type="module" src="/src/main.js"></script>
 </body>
 
-</html>
+</html>

+ 2 - 2
package.json

@@ -1,8 +1,8 @@
 {
   "name": "ruoyi",
   "version": "3.8.6",
-  "description": "若依管理系统",
-  "author": "若依",
+  "description": "亿网管理系统",
+  "author": "亿网",
   "license": "MIT",
   "scripts": {
     "dev": "vite",

文件差異過大導致無法顯示
+ 3 - 0
src/views/components/icons/element-icons.js


+ 87 - 0
src/views/components/icons/index.vue

@@ -0,0 +1,87 @@
+<template>
+  <div class="icons-container">
+    <aside>
+      <a href="#" target="_blank">Add and use
+      </a>
+    </aside>
+    <el-tabs type="border-card">
+      <el-tab-pane label="Icons">
+        <div v-for="item of svgIcons" :key="item">
+          <el-tooltip placement="top">
+            <div slot="content">
+              {{ generateIconCode(item) }}
+            </div>
+            <div class="icon-item">
+              <svg-icon :icon-class="item" class-name="disabled" />
+              <span>{{ item }}</span>
+            </div>
+          </el-tooltip>
+        </div>
+      </el-tab-pane>
+      <el-tab-pane label="Element-UI Icons">
+        <div v-for="item of elementIcons" :key="item">
+          <el-tooltip placement="top">
+            <div slot="content">
+              {{ generateElementIconCode(item) }}
+            </div>
+            <div class="icon-item">
+              <i :class="'el-icon-' + item" />
+              <span>{{ item }}</span>
+            </div>
+          </el-tooltip>
+        </div>
+      </el-tab-pane>
+    </el-tabs>
+  </div>
+</template>
+
+<script>
+import svgIcons from './svg-icons'
+import elementIcons from './element-icons'
+
+export default {
+  name: 'Icons',
+  data() {
+    return {
+      svgIcons,
+      elementIcons
+    }
+  },
+  methods: {
+    generateIconCode(symbol) {
+      return `<svg-icon icon-class="${symbol}" />`
+    },
+    generateElementIconCode(symbol) {
+      return `<i class="el-icon-${symbol}" />`
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.icons-container {
+  margin: 10px 20px 0;
+  overflow: hidden;
+
+  .icon-item {
+    margin: 20px;
+    height: 85px;
+    text-align: center;
+    width: 100px;
+    float: left;
+    font-size: 30px;
+    color: #24292e;
+    cursor: pointer;
+  }
+
+  span {
+    display: block;
+    font-size: 16px;
+    margin-top: 10px;
+  }
+
+  .disabled {
+    pointer-events: none;
+  }
+}
+</style>

+ 10 - 0
src/views/components/icons/svg-icons.js

@@ -0,0 +1,10 @@
+const req = require.context('../../../assets/icons/svg', false, /\.svg$/)
+const requireAll = requireContext => requireContext.keys()
+
+const re = /\.\/(.*)\.svg/
+
+const svgIcons = requireAll(req).map(i => {
+  return i.match(re)[1]
+})
+
+export default svgIcons

+ 102 - 0
src/views/dashboard/BarChart.vue

@@ -0,0 +1,102 @@
+<template>
+  <div :class="className" :style="{height:height,width:width}" />
+</template>
+
+<script>
+import echarts from 'echarts'
+require('echarts/theme/macarons') // echarts theme
+import resize from './mixins/resize'
+
+const animationDuration = 6000
+
+export default {
+  mixins: [resize],
+  props: {
+    className: {
+      type: String,
+      default: 'chart'
+    },
+    width: {
+      type: String,
+      default: '100%'
+    },
+    height: {
+      type: String,
+      default: '300px'
+    }
+  },
+  data() {
+    return {
+      chart: null
+    }
+  },
+  mounted() {
+    this.$nextTick(() => {
+      this.initChart()
+    })
+  },
+  beforeDestroy() {
+    if (!this.chart) {
+      return
+    }
+    this.chart.dispose()
+    this.chart = null
+  },
+  methods: {
+    initChart() {
+      this.chart = echarts.init(this.$el, 'macarons')
+
+      this.chart.setOption({
+        tooltip: {
+          trigger: 'axis',
+          axisPointer: { // 坐标轴指示器,坐标轴触发有效
+            type: 'shadow' // 默认为直线,可选为:'line' | 'shadow'
+          }
+        },
+        grid: {
+          top: 10,
+          left: '2%',
+          right: '2%',
+          bottom: '3%',
+          containLabel: true
+        },
+        xAxis: [{
+          type: 'category',
+          data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
+          axisTick: {
+            alignWithLabel: true
+          }
+        }],
+        yAxis: [{
+          type: 'value',
+          axisTick: {
+            show: false
+          }
+        }],
+        series: [{
+          name: 'pageA',
+          type: 'bar',
+          stack: 'vistors',
+          barWidth: '60%',
+          data: [79, 52, 200, 334, 390, 330, 220],
+          animationDuration
+        }, {
+          name: 'pageB',
+          type: 'bar',
+          stack: 'vistors',
+          barWidth: '60%',
+          data: [80, 52, 200, 334, 390, 330, 220],
+          animationDuration
+        }, {
+          name: 'pageC',
+          type: 'bar',
+          stack: 'vistors',
+          barWidth: '60%',
+          data: [30, 52, 200, 334, 390, 330, 220],
+          animationDuration
+        }]
+      })
+    }
+  }
+}
+</script>

+ 135 - 0
src/views/dashboard/LineChart.vue

@@ -0,0 +1,135 @@
+<template>
+  <div :class="className" :style="{height:height,width:width}" />
+</template>
+
+<script>
+import echarts from 'echarts'
+require('echarts/theme/macarons') // echarts theme
+import resize from './mixins/resize'
+
+export default {
+  mixins: [resize],
+  props: {
+    className: {
+      type: String,
+      default: 'chart'
+    },
+    width: {
+      type: String,
+      default: '100%'
+    },
+    height: {
+      type: String,
+      default: '350px'
+    },
+    autoResize: {
+      type: Boolean,
+      default: true
+    },
+    chartData: {
+      type: Object,
+      required: true
+    }
+  },
+  data() {
+    return {
+      chart: null
+    }
+  },
+  watch: {
+    chartData: {
+      deep: true,
+      handler(val) {
+        this.setOptions(val)
+      }
+    }
+  },
+  mounted() {
+    this.$nextTick(() => {
+      this.initChart()
+    })
+  },
+  beforeDestroy() {
+    if (!this.chart) {
+      return
+    }
+    this.chart.dispose()
+    this.chart = null
+  },
+  methods: {
+    initChart() {
+      this.chart = echarts.init(this.$el, 'macarons')
+      this.setOptions(this.chartData)
+    },
+    setOptions({ expectedData, actualData } = {}) {
+      this.chart.setOption({
+        xAxis: {
+          data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
+          boundaryGap: false,
+          axisTick: {
+            show: false
+          }
+        },
+        grid: {
+          left: 10,
+          right: 10,
+          bottom: 20,
+          top: 30,
+          containLabel: true
+        },
+        tooltip: {
+          trigger: 'axis',
+          axisPointer: {
+            type: 'cross'
+          },
+          padding: [5, 10]
+        },
+        yAxis: {
+          axisTick: {
+            show: false
+          }
+        },
+        legend: {
+          data: ['expected', 'actual']
+        },
+        series: [{
+          name: 'expected', itemStyle: {
+            normal: {
+              color: '#FF005A',
+              lineStyle: {
+                color: '#FF005A',
+                width: 2
+              }
+            }
+          },
+          smooth: true,
+          type: 'line',
+          data: expectedData,
+          animationDuration: 2800,
+          animationEasing: 'cubicInOut'
+        },
+        {
+          name: 'actual',
+          smooth: true,
+          type: 'line',
+          itemStyle: {
+            normal: {
+              color: '#3888fa',
+              lineStyle: {
+                color: '#3888fa',
+                width: 2
+              },
+              areaStyle: {
+                color: '#f3f8ff'
+              }
+            }
+          },
+          data: actualData,
+          animationDuration: 2800,
+          animationEasing: 'quadraticOut'
+        }]
+      })
+    }
+  }
+}
+</script>

+ 181 - 0
src/views/dashboard/PanelGroup.vue

@@ -0,0 +1,181 @@
+<template>
+  <el-row :gutter="40" class="panel-group">
+    <el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
+      <div class="card-panel" @click="handleSetLineChartData('newVisitis')">
+        <div class="card-panel-icon-wrapper icon-people">
+          <svg-icon icon-class="peoples" class-name="card-panel-icon" />
+        </div>
+        <div class="card-panel-description">
+          <div class="card-panel-text">
+            访客
+          </div>
+          <count-to :start-val="0" :end-val="102400" :duration="2600" class="card-panel-num" />
+        </div>
+      </div>
+    </el-col>
+    <el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
+      <div class="card-panel" @click="handleSetLineChartData('messages')">
+        <div class="card-panel-icon-wrapper icon-message">
+          <svg-icon icon-class="message" class-name="card-panel-icon" />
+        </div>
+        <div class="card-panel-description">
+          <div class="card-panel-text">
+            消息
+          </div>
+          <count-to :start-val="0" :end-val="81212" :duration="3000" class="card-panel-num" />
+        </div>
+      </div>
+    </el-col>
+    <el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
+      <div class="card-panel" @click="handleSetLineChartData('purchases')">
+        <div class="card-panel-icon-wrapper icon-money">
+          <svg-icon icon-class="money" class-name="card-panel-icon" />
+        </div>
+        <div class="card-panel-description">
+          <div class="card-panel-text">
+            金额
+          </div>
+          <count-to :start-val="0" :end-val="9280" :duration="3200" class="card-panel-num" />
+        </div>
+      </div>
+    </el-col>
+    <el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
+      <div class="card-panel" @click="handleSetLineChartData('shoppings')">
+        <div class="card-panel-icon-wrapper icon-shopping">
+          <svg-icon icon-class="shopping" class-name="card-panel-icon" />
+        </div>
+        <div class="card-panel-description">
+          <div class="card-panel-text">
+            订单
+          </div>
+          <count-to :start-val="0" :end-val="13600" :duration="3600" class="card-panel-num" />
+        </div>
+      </div>
+    </el-col>
+  </el-row>
+</template>
+
+<script>
+import CountTo from 'vue-count-to'
+
+export default {
+  components: {
+    CountTo
+  },
+  methods: {
+    handleSetLineChartData(type) {
+      this.$emit('handleSetLineChartData', type)
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.panel-group {
+  margin-top: 18px;
+
+  .card-panel-col {
+    margin-bottom: 32px;
+  }
+
+  .card-panel {
+    height: 108px;
+    cursor: pointer;
+    font-size: 12px;
+    position: relative;
+    overflow: hidden;
+    color: #666;
+    background: #fff;
+    box-shadow: 4px 4px 40px rgba(0, 0, 0, .05);
+    border-color: rgba(0, 0, 0, .05);
+
+    &:hover {
+      .card-panel-icon-wrapper {
+        color: #fff;
+      }
+
+      .icon-people {
+        background: #40c9c6;
+      }
+
+      .icon-message {
+        background: #36a3f7;
+      }
+
+      .icon-money {
+        background: #f4516c;
+      }
+
+      .icon-shopping {
+        background: #34bfa3
+      }
+    }
+
+    .icon-people {
+      color: #40c9c6;
+    }
+
+    .icon-message {
+      color: #36a3f7;
+    }
+
+    .icon-money {
+      color: #f4516c;
+    }
+
+    .icon-shopping {
+      color: #34bfa3
+    }
+
+    .card-panel-icon-wrapper {
+      float: left;
+      margin: 14px 0 0 14px;
+      padding: 16px;
+      transition: all 0.38s ease-out;
+      border-radius: 6px;
+    }
+
+    .card-panel-icon {
+      float: left;
+      font-size: 48px;
+    }
+
+    .card-panel-description {
+      float: right;
+      font-weight: bold;
+      margin: 26px;
+      margin-left: 0px;
+
+      .card-panel-text {
+        line-height: 18px;
+        color: rgba(0, 0, 0, 0.45);
+        font-size: 16px;
+        margin-bottom: 12px;
+      }
+
+      .card-panel-num {
+        font-size: 20px;
+      }
+    }
+  }
+}
+
+@media (max-width:550px) {
+  .card-panel-description {
+    display: none;
+  }
+
+  .card-panel-icon-wrapper {
+    float: none !important;
+    width: 100%;
+    height: 100%;
+    margin: 0 !important;
+
+    .svg-icon {
+      display: block;
+      margin: 14px auto !important;
+      float: none !important;
+    }
+  }
+}
+</style>

+ 79 - 0
src/views/dashboard/PieChart.vue

@@ -0,0 +1,79 @@
+<template>
+  <div :class="className" :style="{height:height,width:width}" />
+</template>
+
+<script>
+import echarts from 'echarts'
+require('echarts/theme/macarons') // echarts theme
+import resize from './mixins/resize'
+
+export default {
+  mixins: [resize],
+  props: {
+    className: {
+      type: String,
+      default: 'chart'
+    },
+    width: {
+      type: String,
+      default: '100%'
+    },
+    height: {
+      type: String,
+      default: '300px'
+    }
+  },
+  data() {
+    return {
+      chart: null
+    }
+  },
+  mounted() {
+    this.$nextTick(() => {
+      this.initChart()
+    })
+  },
+  beforeDestroy() {
+    if (!this.chart) {
+      return
+    }
+    this.chart.dispose()
+    this.chart = null
+  },
+  methods: {
+    initChart() {
+      this.chart = echarts.init(this.$el, 'macarons')
+
+      this.chart.setOption({
+        tooltip: {
+          trigger: 'item',
+          formatter: '{a} <br/>{b} : {c} ({d}%)'
+        },
+        legend: {
+          left: 'center',
+          bottom: '10',
+          data: ['Industries', 'Technology', 'Forex', 'Gold', 'Forecasts']
+        },
+        series: [
+          {
+            name: 'WEEKLY WRITE ARTICLES',
+            type: 'pie',
+            roseType: 'radius',
+            radius: [15, 95],
+            center: ['50%', '38%'],
+            data: [
+              { value: 320, name: 'Industries' },
+              { value: 240, name: 'Technology' },
+              { value: 149, name: 'Forex' },
+              { value: 100, name: 'Gold' },
+              { value: 59, name: 'Forecasts' }
+            ],
+            animationEasing: 'cubicInOut',
+            animationDuration: 2600
+          }
+        ]
+      })
+    }
+  }
+}
+</script>

+ 116 - 0
src/views/dashboard/RaddarChart.vue

@@ -0,0 +1,116 @@
+<template>
+  <div :class="className" :style="{height:height,width:width}" />
+</template>
+
+<script>
+import echarts from 'echarts'
+require('echarts/theme/macarons') // echarts theme
+import resize from './mixins/resize'
+
+const animationDuration = 3000
+
+export default {
+  mixins: [resize],
+  props: {
+    className: {
+      type: String,
+      default: 'chart'
+    },
+    width: {
+      type: String,
+      default: '100%'
+    },
+    height: {
+      type: String,
+      default: '300px'
+    }
+  },
+  data() {
+    return {
+      chart: null
+    }
+  },
+  mounted() {
+    this.$nextTick(() => {
+      this.initChart()
+    })
+  },
+  beforeDestroy() {
+    if (!this.chart) {
+      return
+    }
+    this.chart.dispose()
+    this.chart = null
+  },
+  methods: {
+    initChart() {
+      this.chart = echarts.init(this.$el, 'macarons')
+
+      this.chart.setOption({
+        tooltip: {
+          trigger: 'axis',
+          axisPointer: { // 坐标轴指示器,坐标轴触发有效
+            type: 'shadow' // 默认为直线,可选为:'line' | 'shadow'
+          }
+        },
+        radar: {
+          radius: '66%',
+          center: ['50%', '42%'],
+          splitNumber: 8,
+          splitArea: {
+            areaStyle: {
+              color: 'rgba(127,95,132,.3)',
+              opacity: 1,
+              shadowBlur: 45,
+              shadowColor: 'rgba(0,0,0,.5)',
+              shadowOffsetX: 0,
+              shadowOffsetY: 15
+            }
+          },
+          indicator: [
+            { name: 'Sales', max: 10000 },
+            { name: 'Administration', max: 20000 },
+            { name: 'Information Techology', max: 20000 },
+            { name: 'Customer Support', max: 20000 },
+            { name: 'Development', max: 20000 },
+            { name: 'Marketing', max: 20000 }
+          ]
+        },
+        legend: {
+          left: 'center',
+          bottom: '10',
+          data: ['Allocated Budget', 'Expected Spending', 'Actual Spending']
+        },
+        series: [{
+          type: 'radar',
+          symbolSize: 0,
+          areaStyle: {
+            normal: {
+              shadowBlur: 13,
+              shadowColor: 'rgba(0,0,0,.2)',
+              shadowOffsetX: 0,
+              shadowOffsetY: 10,
+              opacity: 1
+            }
+          },
+          data: [
+            {
+              value: [5000, 7000, 12000, 11000, 15000, 14000],
+              name: 'Allocated Budget'
+            },
+            {
+              value: [4000, 9000, 15000, 15000, 13000, 11000],
+              name: 'Expected Spending'
+            },
+            {
+              value: [5500, 11000, 12000, 15000, 12000, 12000],
+              name: 'Actual Spending'
+            }
+          ],
+          animationDuration: animationDuration
+        }]
+      })
+    }
+  }
+}
+</script>

+ 56 - 0
src/views/dashboard/mixins/resize.js

@@ -0,0 +1,56 @@
+import { debounce } from '@/utils'
+
+export default {
+  data() {
+    return {
+      $_sidebarElm: null,
+      $_resizeHandler: null
+    }
+  },
+  mounted() {
+    this.initListener()
+  },
+  activated() {
+    if (!this.$_resizeHandler) {
+      // avoid duplication init
+      this.initListener()
+    }
+
+    // when keep-alive chart activated, auto resize
+    this.resize()
+  },
+  beforeDestroy() {
+    this.destroyListener()
+  },
+  deactivated() {
+    this.destroyListener()
+  },
+  methods: {
+    // use $_ for mixins properties
+    // https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential
+    $_sidebarResizeHandler(e) {
+      if (e.propertyName === 'width') {
+        this.$_resizeHandler()
+      }
+    },
+    initListener() {
+      this.$_resizeHandler = debounce(() => {
+        this.resize()
+      }, 100)
+      window.addEventListener('resize', this.$_resizeHandler)
+
+      this.$_sidebarElm = document.getElementsByClassName('sidebar-container')[0]
+      this.$_sidebarElm && this.$_sidebarElm.addEventListener('transitionend', this.$_sidebarResizeHandler)
+    },
+    destroyListener() {
+      window.removeEventListener('resize', this.$_resizeHandler)
+      this.$_resizeHandler = null
+
+      this.$_sidebarElm && this.$_sidebarElm.removeEventListener('transitionend', this.$_sidebarResizeHandler)
+    },
+    resize() {
+      const { chart } = this
+      chart && chart.resize()
+    }
+  }
+}

+ 79 - 0
src/views/example/demo/demoForm.vue

@@ -0,0 +1,79 @@
+<template>
+  <div>
+    <!--查看和审批对话框-->
+    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
+      <el-form ref="form" :model="form" label-width="100px">
+        <el-form-item label="申请编号" prop="applyNum">
+          <el-input v-model="form.applyNum" :readonly="taskName!=='调整申请'" />
+        </el-form-item>
+        <el-form-item label="是否高压停电">
+          <el-radio-group v-model="form.highVoltage" :disabled="taskName!=='调整申请'">
+            <el-radio label="0">否</el-radio>
+            <el-radio label="1">是</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="申请人" prop="applyUserName">
+          <el-input v-model="form.applyUserName" :readonly="taskName!=='调整申请'" />
+        </el-form-item>
+        <el-form-item label="申请时间" prop="applyTime">
+          <el-date-picker clearable size="small" style="width: 200px"
+                          v-model="form.applyTime"
+                          type="date"
+                          value-format="yyyy-MM-dd"
+                          placeholder="选择申请时间"
+                          :readonly="taskName!=='调整申请'">
+          </el-date-picker>
+        </el-form-item>
+        <!--<el-form-item label="流程实例ID" prop="instanceId">
+          <el-input v-model="form.instanceId" readonly />
+        </el-form-item>-->
+        <el-form-item label="备注" prop="remark">
+          <el-input v-model="form.remark" type="textarea" :readonly="taskName!=='调整申请'" />
+        </el-form-item>
+      </el-form>
+      <view-verify
+        :open.sync="open"
+        :row="row"
+        :taskId="taskId"
+        :type="type"
+      />
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+  import ViewVerify from "@/components/Activiti/ViewVerify/index";
+
+  export default {
+    name: "DemoForm",
+    components: {
+      ViewVerify,
+    },
+    props: {
+      row: {
+        type: Object,
+      },
+      taskId: {
+        type: String,
+      },
+      taskName: {
+        type: String,
+      },
+      type: {
+        type: String,
+        default: 'none',
+      },
+    },
+    data() {
+      return {
+        title: '查看示例Demo',
+        form: this.row,
+        open: false,
+      }
+    },
+  }
+</script>
+
+<style scoped>
+
+</style>

+ 396 - 0
src/views/example/demo/index.vue

@@ -0,0 +1,396 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="申请编号" prop="applyNum">
+        <el-input
+          v-model="queryParams.applyNum"
+          placeholder="请输入申请编号"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="高压停电" prop="highVoltage">
+        <el-select v-model="queryParams.highVoltage" placeholder="请选择是否高压停电" clearable size="small">
+          <el-option label="否" value="0" />
+          <el-option label="是" value="1" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="申请人" prop="applyUserName">
+        <el-input
+          v-model="queryParams.applyUserName"
+          placeholder="请输入申请人"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="申请时间" prop="applyTime">
+        <el-date-picker clearable size="small" style="width: 200px"
+          v-model="queryParams.applyTime"
+          type="date"
+          value-format="yyyy-MM-dd"
+          placeholder="选择申请时间">
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item label="流程实例" prop="instanceId">
+        <el-input
+          v-model="queryParams.instanceId"
+          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">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['example:demo:add']"
+        >新增</el-button>
+      </el-col>
+	  <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="demoList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="ID" align="center" prop="id" width="60" />
+      <el-table-column label="申请编号" align="center" prop="applyNum" width="120" />
+      <el-table-column label="是否高压停电" align="center" prop="highVoltage" width="100">
+        <template slot-scope="scope">
+          <span>{{ scope.row.highVoltage === '0' ? '否' : '是' }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="申请人" align="center" prop="applyUserName" width="90" />
+      <el-table-column label="申请时间" align="center" prop="applyTime" width="180" />
+      <el-table-column label="流程实例ID" align="center" prop="instanceId" width="100" />
+      <el-table-column label="备注" align="center" prop="remark" width="180" />
+      <el-table-column label="当前任务名称" align="center" prop="taskName" width="150" />
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <!--本案例提交申请前有做会签参与人选择的操作,因此不引入 ApplyBefore 子组件-->
+          <el-button
+            v-show="!scope.row.instanceId"
+            size="mini"
+            type="text"
+            icon="el-icon-check"
+            @click="handleApplyView(scope.row)"
+          >提交申请</el-button>
+          <el-button
+            v-show="!scope.row.instanceId"
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+          >修改</el-button>
+          <el-button
+            v-show="!scope.row.instanceId"
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+          >删除</el-button>
+          <apply-after
+            v-show="scope.row.instanceId"
+            :row="scope.row"
+            :taskId="scope.row.taskId"
+            :type="scope.row.type"
+            @getList="getList"
+          ></apply-after>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改示例Demo对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="100px">
+        <el-form-item label="申请编号" prop="applyNum">
+          <el-input v-model="form.applyNum" placeholder="请输入申请编号" />
+        </el-form-item>
+        <el-form-item label="是否高压停电">
+          <el-radio-group v-model="form.highVoltage">
+            <el-radio label="0">否</el-radio>
+            <el-radio label="1">是</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+          <el-input v-model="form.remark" 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>
+
+    <!--选择会签参与人对话框-->
+    <el-dialog title="选择调度会会签参与人" :visible.sync="showSelectUser" width="400px" append-to-body>
+      <el-form ref="selectUserForm" :rules="selectUserRules" label-width="80px">
+        <el-form-item label="参与人">
+          <el-select v-model="userNames" multiple placeholder="请选择">
+            <el-option
+              v-for="item in userOptions"
+              :key="item.userId"
+              :label="item.nickName"
+              :value="item.userName"
+              :disabled="item.status === 1"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="handleApply">确 定</el-button>
+        <el-button @click="userNames=[];showSelectUser=false">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listDemo, getDemo, delDemo, addDemo, updateDemo, exportDemo } from "@/api/example/demo";
+import ApplyBefore from "@/components/Activiti/ApplyBefore/index";
+import ApplyAfter from "@/components/Activiti/ApplyAfter/index";
+import { listUser } from "@/api/system/user";
+import request from '@/utils/request'
+
+export default {
+  name: "Demo",
+  components: {
+    ApplyBefore,
+    ApplyAfter,
+  },
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 示例Demo表格数据
+      demoList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        applyNum: null,
+        highVoltage: null,
+        attachment: null,
+        applyUserId: null,
+        applyUserName: null,
+        applyTime: null,
+        instanceId: null,
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        applyNum: [
+          { required: true, message: "申请编号不能为空", trigger: "blur" }
+        ],
+        highVoltage: [
+          { required: true, message: "是否高压停电不能为空", trigger: "blur" }
+        ],
+      },
+      requestMapping: '/example/demo',
+
+      selectedRow: {},
+      selectUserForm: {},
+      showSelectUser: false,
+      selectUserRules: {
+        userOptions: [
+          { required: true, message: '参与人不能为空', trigger: 'blur' },
+        ],
+      },
+      userOptions: [],
+      userNames: [],
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 查询示例Demo列表 */
+    getList() {
+      this.loading = true;
+      listDemo(this.queryParams).then(response => {
+        this.demoList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      }).then(() => {
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        applyNum: null,
+        highVoltage: "0",
+        attachment: null,
+        applyUserId: null,
+        applyUserName: null,
+        applyTime: null,
+        instanceId: null,
+        delFlag: null,
+        createBy: null,
+        createTime: null,
+        updateBy: null,
+        updateTime: null,
+        remark: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加示例Demo";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getDemo(id).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改示例Demo";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.id != null) {
+            updateDemo(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addDemo(this.form).then(response => {
+              this.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认删除示例Demo编号为"' + ids + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return delDemo(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        })
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有示例Demo数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return exportDemo(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+        })
+    },
+    handleApply: function () {
+      if (this.userNames.length === 0) {
+        this.msgError('请先选择会签参与人');
+        return;
+      }
+      const selectedRow = this.selectedRow;
+      const requestMapping = this.requestMapping;
+      const userNames = this.userNames.toString();
+      this.$confirm('是否提交ID为"' + selectedRow.id + '"的申请单据?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(function() {
+        return request({
+          url: requestMapping + '/submitApply/' + selectedRow.id,
+          method: 'post',
+          params: { "variablesStr": { "gytd": selectedRow.highVoltage, "users": userNames } },
+        });
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("申请成功");
+        this.userNames = [];
+        this.showSelectUser = false;
+      })
+    },
+
+    handleApplyView(row) {
+      this.selectedRow = row;
+      this.showSelectUser = true;
+      this.getUserList();
+    },
+
+    /** 查询用户列表 */
+    getUserList() {
+      listUser().then(response => {
+          this.userOptions = response.rows;
+        }
+      );
+    },
+
+  }
+};
+</script>

+ 356 - 0
src/views/leave/leave/index.vue

@@ -0,0 +1,356 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="请假类型" prop="type">
+        <el-select v-model="queryParams.type" placeholder="请选择请假类型" clearable size="small">
+          <el-option
+            v-for="dict in typeOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="标题" prop="title">
+        <el-input
+          v-model="queryParams.title"
+          placeholder="请输入标题"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="实例ID" prop="instanceId">
+        <el-input
+          v-model="queryParams.instanceId"
+          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">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['leave:leave:add']"
+        >新增</el-button>
+      </el-col>
+	  <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="leaveList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="ID" align="center" prop="id" width="40" />
+      <el-table-column label="请假类型" align="center" prop="type" :formatter="typeFormat" width="75" />
+      <el-table-column label="标题" align="center" prop="title" width="140" />
+      <el-table-column label="原因" align="center" prop="reason" width="120" />
+      <el-table-column label="开始时间" align="center" prop="leaveStartTime" width="120">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.leaveStartTime, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="结束时间" align="center" prop="leaveEndTime" width="120">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.leaveEndTime, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <!--<el-table-column label="请假时长" align="center" prop="totalTime" />-->
+      <el-table-column label="流程实例ID" align="center" prop="instanceId" />
+      <el-table-column label="申请人" align="center" prop="applyUserName" />
+      <el-table-column label="申请时间" align="center" prop="applyTime" width="120">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.applyTime, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="当前任务名称" align="center" prop="taskName" width="150" />
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <apply-before
+            v-show="!scope.row.instanceId"
+            :row="scope.row"
+            :handleUpdate="handleUpdate"
+            :handleDelete="handleDelete"
+            :requestMapping="requestMapping"
+            @getList="getList"
+          ></apply-before>
+          <apply-after
+            v-show="scope.row.instanceId"
+            :row="scope.row"
+            :taskId="scope.row.taskId"
+            :type="scope.row.type"
+            @getList="getList"
+          ></apply-after>
+        </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="请假类型" prop="type">
+          <el-select v-model="form.type" placeholder="请选择请假类型">
+            <el-option
+              v-for="dict in typeOptions"
+              :key="dict.dictValue"
+              :label="dict.dictLabel"
+              :value="dict.dictValue"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="标题" prop="title">
+          <el-input v-model="form.title" placeholder="请输入标题" />
+        </el-form-item>
+        <el-form-item label="原因" prop="reason">
+          <el-input v-model="form.reason" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+        <el-form-item label="开始时间" prop="leaveStartTime">
+          <el-date-picker clearable size="small" style="width: 200px"
+            v-model="form.leaveStartTime"
+            type="date"
+            value-format="yyyy-MM-dd"
+            placeholder="选择开始时间">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="结束时间" prop="leaveEndTime">
+          <el-date-picker clearable size="small" style="width: 200px"
+            v-model="form.leaveEndTime"
+            type="date"
+            value-format="yyyy-MM-dd"
+            placeholder="选择结束时间">
+          </el-date-picker>
+        </el-form-item>
+        <!--<el-form-item label="请假时长" prop="totalTime">
+          <el-input v-model="form.totalTime" readonly />
+        </el-form-item>-->
+        <el-form-item label="备注" prop="remark">
+          <el-input v-model="form.remark" 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 { listLeave, getLeave, delLeave, addLeave, updateLeave, exportLeave } from "@/api/leave/leave";
+import ApplyBefore from "@/components/Activiti/ApplyBefore/index";
+import ApplyAfter from "@/components/Activiti/ApplyAfter/index";
+
+export default {
+  name: "Leave",
+  components: {
+    ApplyBefore,
+    ApplyAfter,
+  },
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 请假表格数据
+      leaveList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 请假类型字典
+      typeOptions: [],
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        type: null,
+        title: null,
+        leaveStartTime: null,
+        leaveEndTime: null,
+        applyUserId: null,
+        applyUserName: null,
+        applyTime: null,
+        instanceId: null,
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        type: [
+          { required: true, message: "请假类型不能为空", trigger: "blur" },
+        ],
+        title: [
+          { required: true, message: "标题不能为空", trigger: "blur" },
+        ],
+        reason: [
+          { required: true, message: "原因不能为空", trigger: "blur" },
+        ],
+        leaveStartTime: [
+          { required: true, message: "开始时间不能为空", trigger: "blur" },
+        ],
+        leaveEndTime: [
+          { required: true, message: "结束时间不能为空", trigger: "blur" },
+        ],
+      },
+      requestMapping: '/leave/leave',
+    };
+  },
+  created() {
+    this.getList();
+    this.getDicts("biz_leave_type").then(response => {
+      this.typeOptions = response.data;
+    });
+  },
+  methods: {
+    /** 查询请假列表 */
+    getList() {
+      this.loading = true;
+      listLeave(this.queryParams).then(response => {
+        this.leaveList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 请假类型字典翻译
+    typeFormat(row, column) {
+      return this.selectDictLabel(this.typeOptions, row.type);
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        type: null,
+        title: null,
+        reason: null,
+        leaveStartTime: null,
+        leaveEndTime: null,
+        totalTime: null,
+        realityStartTime: null,
+        realityEndTime: null,
+        applyUserId: null,
+        applyUserName: null,
+        applyTime: null,
+        instanceId: null,
+        processKey: null,
+        delFlag: null,
+        createBy: null,
+        createTime: null,
+        updateBy: null,
+        updateTime: null,
+        remark: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加请假";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getLeave(id).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改请假";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.id != null) {
+            updateLeave(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addLeave(this.form).then(response => {
+              this.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认删除请假编号为"' + ids + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return delLeave(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        })
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有请假数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return exportLeave(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+        })
+    }
+  }
+};
+</script>

+ 153 - 0
src/views/leave/leave/leaveForm.vue

@@ -0,0 +1,153 @@
+<template>
+  <div>
+    <!--查看和审批对话框-->
+    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="120px">
+        <el-form-item label="请假类型" prop="type">
+          <el-select v-model="form.type" :disabled="taskName!=='调整申请'">
+            <el-option
+              v-for="dict in typeOptions"
+              :key="dict.dictValue"
+              :label="dict.dictLabel"
+              :value="dict.dictValue"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="标题" prop="title">
+          <el-input v-model="form.title" :readonly="taskName!=='调整申请'" />
+        </el-form-item>
+        <el-form-item label="原因" prop="reason">
+          <el-input v-model="form.reason" type="textarea" :readonly="taskName!=='调整申请'" />
+        </el-form-item>
+        <el-form-item label="开始时间" prop="leaveStartTime">
+          <el-date-picker clearable size="small" style="width: 200px"
+                          v-model="form.leaveStartTime"
+                          type="date"
+                          value-format="yyyy-MM-dd"
+                          :readonly="taskName!=='调整申请'">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="结束时间" prop="leaveEndTime">
+          <el-date-picker clearable size="small" style="width: 200px"
+                          v-model="form.leaveEndTime"
+                          type="date"
+                          value-format="yyyy-MM-dd"
+                          :readonly="taskName!=='调整申请'">
+          </el-date-picker>
+        </el-form-item>
+        <!--<el-form-item label="请假时长" prop="totalTime">
+          <el-input v-model="form.totalTime" readonly />
+        </el-form-item>-->
+        <el-form-item label="实际开始时间" prop="realityStartTime" v-if="taskName==='销假' || type !== 'todo'">
+          <el-date-picker clearable size="small" style="width: 200px"
+                          v-model="form.realityStartTime"
+                          type="date"
+                          value-format="yyyy-MM-dd"
+                          placeholder="选择实际开始时间"
+                          :readonly="taskName!=='销假'">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="实际结束时间" prop="realityEndTime" v-if="taskName==='销假' || type !== 'todo'">
+          <el-date-picker clearable size="small" style="width: 200px"
+                          v-model="form.realityEndTime"
+                          type="date"
+                          value-format="yyyy-MM-dd"
+                          placeholder="选择实际结束时间"
+                          :readonly="taskName!=='销假'">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="申请人" prop="applyUserName">
+          <el-input v-model="form.applyUserName" readonly />
+        </el-form-item>
+        <el-form-item label="申请时间" prop="applyTime">
+          <el-date-picker clearable size="small" style="width: 200px"
+                          v-model="form.applyTime"
+                          type="date"
+                          value-format="yyyy-MM-dd"
+                          readonly>
+          </el-date-picker>
+        </el-form-item>
+        <!--<el-form-item label="流程实例ID" prop="instanceId">
+          <el-input v-model="form.instanceId" readonly />
+        </el-form-item>-->
+        <el-form-item label="备注" prop="remark">
+          <el-input v-model="form.remark" type="textarea" :readonly="taskName!=='调整申请'" />
+        </el-form-item>
+      </el-form>
+      <view-verify
+        :open.sync="open"
+        :row="row"
+        :taskId="taskId"
+        :type="type"
+      />
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+  import ViewVerify from "@/components/Activiti/ViewVerify/index";
+
+  export default {
+    name: "LeaveForm",
+    components: {
+      ViewVerify,
+    },
+    props: {
+      row: {
+        type: Object,
+      },
+      taskId: {
+        type: String,
+      },
+      taskName: {
+        type: String,
+      },
+      type: {
+        type: String,
+        default: 'none',
+      },
+    },
+    data() {
+      return {
+        title: '查看请假表单',
+        form: this.row,
+        open: false,
+        // 请假类型字典
+        typeOptions: [],
+        // 表单校验
+        rules: {
+          type: [
+            { required: true, message: "请假类型不能为空", trigger: "blur" },
+          ],
+          title: [
+            { required: true, message: "标题不能为空", trigger: "blur" },
+          ],
+          reason: [
+            { required: true, message: "原因不能为空", trigger: "blur" },
+          ],
+          leaveStartTime: [
+            { required: true, message: "开始时间不能为空", trigger: "blur" },
+          ],
+          leaveEndTime: [
+            { required: true, message: "结束时间不能为空", trigger: "blur" },
+          ],
+          realityStartTime: [
+            { required: true, message: "实际开始时间不能为空", trigger: "blur" },
+          ],
+          realityEndTime: [
+            { required: true, message: "实际结束时间不能为空", trigger: "blur" },
+          ],
+        },
+      }
+    },
+    created() {
+      this.getDicts("biz_leave_type").then(response => {
+        this.typeOptions = response.data;
+      });
+    },
+  }
+</script>
+
+<style scoped>
+
+</style>

+ 229 - 0
src/views/todoItem/done/index.vue

@@ -0,0 +1,229 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="任务ID" prop="taskId">
+        <el-input
+          v-model="queryParams.taskId"
+          placeholder="请输入任务ID"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="任务名称" prop="taskName">
+        <el-input
+          v-model="queryParams.taskName"
+          placeholder="任务名称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="流程实例" prop="instanceId">
+        <el-input
+          v-model="queryParams.instanceId"
+          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="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="taskList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="任务ID" align="center" prop="taskId" width="150" />
+      <el-table-column label="任务名称" align="center" prop="taskName" width="150" />
+      <el-table-column label="流程实例ID" align="center" prop="instanceId" width="150" />
+      <el-table-column label="办理人" align="center" prop="assigneeName" width="150" />
+      <el-table-column label="开始时间" align="center" prop="startTime" width="150" />
+      <el-table-column label="结束时间" align="center" prop="endTime" width="180" />
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <apply-after
+            v-if="scope.row.instanceId"
+            :row="scope.row.formData"
+            :taskId="scope.row.taskId"
+            :type="scope.row.type"
+            @getList="getList"
+          ></apply-after>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+  </div>
+</template>
+
+<script>
+  import request from '@/utils/request'
+  import ApplyAfter from "@/components/Activiti/ApplyAfter/index";
+
+  export default {
+    name: "Done",
+    components: {
+      ApplyAfter,
+    },
+    data() {
+      return {
+        // 遮罩层
+        loading: true,
+        // 选中数组
+        ids: [],
+        // 非单个禁用
+        single: true,
+        // 非多个禁用
+        multiple: true,
+        // 显示搜索条件
+        showSearch: true,
+        // 总条数
+        total: 0,
+        // 已办表格数据
+        taskList: [],
+        // 弹出层标题
+        title: "",
+        // 是否显示弹出层
+        open: false,
+        // 查询参数
+        queryParams: {
+          pageNum: 1,
+          pageSize: 10,
+          taskId: null,
+          taskName: null,
+        },
+        // 表单参数
+        form: {},
+        // 表单校验
+        rules: {
+        },
+      };
+    },
+    created() {
+      this.getList();
+    },
+    methods: {
+      /** 查询已办列表 */
+      getList() {
+        this.loading = true;
+        return request({
+          url: '/activiti/process/taskDoneList',
+          method: 'get',
+          params: this.queryParams
+        }).then(response => {
+          this.taskList = response.rows;
+          this.total = response.total;
+          this.loading = false;
+        }).then(() => {
+        });
+      },
+      // 取消按钮
+      cancel() {
+        this.open = false;
+        this.reset();
+      },
+      // 表单重置
+      reset() {
+        this.form = {
+          id: null,
+          taskId: null,
+          taskName: null,
+        };
+        this.resetForm("form");
+      },
+      /** 搜索按钮操作 */
+      handleQuery() {
+        this.queryParams.pageNum = 1;
+        this.getList();
+      },
+      /** 重置按钮操作 */
+      resetQuery() {
+        this.resetForm("queryForm");
+        this.handleQuery();
+      },
+      // 多选框选中数据
+      handleSelectionChange(selection) {
+        this.ids = selection.map(item => item.id)
+        this.single = selection.length!==1
+        this.multiple = !selection.length
+      },
+      /** 新增按钮操作 */
+      handleAdd() {
+        this.reset();
+        this.open = true;
+        this.title = "添加已办";
+      },
+      /** 修改按钮操作 */
+      handleUpdate(row) {
+        this.reset();
+        const id = row.id || this.ids
+        getDemo(id).then(response => {
+          this.form = response.data;
+          this.open = true;
+          this.title = "修改已办";
+        });
+      },
+      /** 提交按钮 */
+      submitForm() {
+        this.$refs["form"].validate(valid => {
+          if (valid) {
+            if (this.form.id != null) {
+              updateDemo(this.form).then(response => {
+                this.msgSuccess("修改成功");
+                this.open = false;
+                this.getList();
+              });
+            } else {
+              addDemo(this.form).then(response => {
+                this.msgSuccess("新增成功");
+                this.open = false;
+                this.getList();
+              });
+            }
+          }
+        });
+      },
+      /** 删除按钮操作 */
+      handleDelete(row) {
+        const ids = row.id || this.ids;
+        this.$confirm('是否确认删除已办编号为"' + ids + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return delDemo(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        })
+      },
+      /** 导出按钮操作 */
+      handleExport() {
+        const queryParams = this.queryParams;
+        this.$confirm('是否确认导出所有已办数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return exportDemo(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+        })
+      },
+    }
+  };
+</script>

+ 229 - 0
src/views/todoItem/todo/index.vue

@@ -0,0 +1,229 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="任务ID" prop="taskId">
+        <el-input
+          v-model="queryParams.taskId"
+          placeholder="请输入任务ID"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="任务名称" prop="taskName">
+        <el-input
+          v-model="queryParams.taskName"
+          placeholder="任务名称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="流程实例" prop="instanceId">
+        <el-input
+          v-model="queryParams.instanceId"
+          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="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="taskList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="任务ID" align="center" prop="taskId" width="150" />
+      <el-table-column label="任务名称" align="center" prop="taskName" width="150" />
+      <el-table-column label="流程实例ID" align="center" prop="instanceId" width="150" />
+      <el-table-column label="待办人" align="center" prop="assigneeName" width="150" />
+      <el-table-column label="创建时间" align="center" prop="createTime" width="180" />
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <apply-after
+            v-if="scope.row.instanceId"
+            :row="scope.row.formData"
+            :taskId="scope.row.taskId"
+            :taskName="scope.row.taskName"
+            :type="scope.row.type"
+            @getList="getList"
+          ></apply-after>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+  </div>
+</template>
+
+<script>
+  import request from '@/utils/request'
+  import ApplyAfter from "@/components/Activiti/ApplyAfter/index";
+
+  export default {
+    name: "Todo",
+    components: {
+      ApplyAfter,
+    },
+    data() {
+      return {
+        // 遮罩层
+        loading: true,
+        // 选中数组
+        ids: [],
+        // 非单个禁用
+        single: true,
+        // 非多个禁用
+        multiple: true,
+        // 显示搜索条件
+        showSearch: true,
+        // 总条数
+        total: 0,
+        // 待办表格数据
+        taskList: [],
+        // 弹出层标题
+        title: "",
+        // 是否显示弹出层
+        open: false,
+        // 查询参数
+        queryParams: {
+          pageNum: 1,
+          pageSize: 10,
+          taskId: null,
+          taskName: null,
+        },
+        // 表单参数
+        form: {},
+        // 表单校验
+        rules: {
+        },
+      };
+    },
+    created() {
+      this.getList();
+    },
+    methods: {
+      /** 查询待办列表 */
+      getList() {
+        this.loading = true;
+        return request({
+          url: '/activiti/process/taskList',
+          method: 'get',
+          params: this.queryParams
+        }).then(response => {
+          this.taskList = response.rows;
+          this.total = response.total;
+          this.loading = false;
+        }).then(() => {
+        });
+      },
+      // 取消按钮
+      cancel() {
+        this.open = false;
+        this.reset();
+      },
+      // 表单重置
+      reset() {
+        this.form = {
+          id: null,
+          taskId: null,
+          taskName: null,
+        };
+        this.resetForm("form");
+      },
+      /** 搜索按钮操作 */
+      handleQuery() {
+        this.queryParams.pageNum = 1;
+        this.getList();
+      },
+      /** 重置按钮操作 */
+      resetQuery() {
+        this.resetForm("queryForm");
+        this.handleQuery();
+      },
+      // 多选框选中数据
+      handleSelectionChange(selection) {
+        this.ids = selection.map(item => item.id)
+        this.single = selection.length!==1
+        this.multiple = !selection.length
+      },
+      /** 新增按钮操作 */
+      handleAdd() {
+        this.reset();
+        this.open = true;
+        this.title = "添加待办";
+      },
+      /** 修改按钮操作 */
+      handleUpdate(row) {
+        this.reset();
+        const id = row.id || this.ids
+        getDemo(id).then(response => {
+          this.form = response.data;
+          this.open = true;
+          this.title = "修改待办";
+        });
+      },
+      /** 提交按钮 */
+      submitForm() {
+        this.$refs["form"].validate(valid => {
+          if (valid) {
+            if (this.form.id != null) {
+              updateDemo(this.form).then(response => {
+                this.msgSuccess("修改成功");
+                this.open = false;
+                this.getList();
+              });
+            } else {
+              addDemo(this.form).then(response => {
+                this.msgSuccess("新增成功");
+                this.open = false;
+                this.getList();
+              });
+            }
+          }
+        });
+      },
+      /** 删除按钮操作 */
+      handleDelete(row) {
+        const ids = row.id || this.ids;
+        this.$confirm('是否确认删除待办编号为"' + ids + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return delDemo(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        })
+      },
+      /** 导出按钮操作 */
+      handleExport() {
+        const queryParams = this.queryParams;
+        this.$confirm('是否确认导出所有待办数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return exportDemo(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+        })
+      },
+    }
+  };
+</script>