lex 2 年 前
コミット
c4fa2e9a0e

+ 38 - 0
src/components/save-form/README.md

@@ -0,0 +1,38 @@
+#### save-form
+
+背景:为保存当页搜索数据,并且不使用keepAlive
+
+###### 使用方法:
+
+``` html
+<saveform :model="form">
+  <el-form-item prop="input">
+    <el-input v-model="form.input">
+  </el-form-item>
+</saveform>
+```
+
+使用时改动较小,仅须将`el-form`修改为`saveform`即可,组件会在验证通过后自动保存当前表单数据,在reset时自动清空数据
+
+数据保存使用的是`localStorage`故关闭标签后数据会自动清空
+
+###### 翻页保存:
+``` html
+<pagination
+  :total.sync="rules.total"
+  :page.sync="rules.page"
+  :limit.sync="rules.limit"
+  :page-sizes="rules.page_size"
+  :sync="true"
+  @pagination="getList"
+/>
+```
+请按照以上示例使用翻页,添加了`sync`字段使用此字段才会保存翻页数据
+
+###### 其他:
+请在`@/router/notKeepAliveList`中添加当页路由,保证当前页面不会keepAlive
+
+##### 已知问题
+
+1. 点击重置按钮无效
+请添加`noclear`属性

+ 124 - 0
src/components/save-form/index.vue

@@ -0,0 +1,124 @@
+<template>
+  <el-form
+    class="save-form"
+    v-bind="{ ...$attrs, ...$props }"
+    v-on="$listeners"
+    @submit.stop.native="submit"
+    @reset.stop.native="reset"
+    ref="form"
+  >
+    <slot />
+  </el-form>
+</template>
+<script>
+import { Searchs } from "@/helpers";
+export default {
+  name: "save-form",
+  props: ["model", "save-key", "noclear"],
+  data() {
+    return {
+      searchs: null
+    };
+  },
+
+  created() {
+    this.setFormValue();
+  },
+  methods: {
+    setFormValue() {
+      const searchs = new Searchs(this.saveKey || this.$route.path);
+      this.searchs = searchs;
+      const active = searchs.get();
+      for (const key in active.form) {
+        if (active.form.hasOwnProperty(key)) {
+          const item = active.form[key];
+          this.model[key] = item;
+        }
+      }
+      // console.log(active, "showInfo", this.$route.path);
+      if (this.saveKey) {
+        this.searchs.update(this.$route.path, undefined, "bind");
+      }
+    },
+    submit(evt) {
+      evt.stopPropagation();
+      evt.stopImmediatePropagation();
+      evt.preventDefault();
+      if (this.saveKey) {
+        this.searchs.update(this.$route.path, undefined, "bind");
+      }
+      this.searchs.update(this.model, undefined, "form");
+      //  (  new Searchs().searchs)
+      if (this.$listeners.submit) {
+        this.$listeners.submit(evt);
+      }
+    },
+    reset(evt) {
+      evt.stopPropagation();
+      evt.stopImmediatePropagation();
+      evt.preventDefault();
+      let setItemEvent = new Event("watchStorage");
+      window.dispatchEvent(setItemEvent);
+
+      if (this.$listeners.reset) {
+        if (this.noclear == undefined) {
+          this.$nextTick(() => {
+            this.resetFields();
+            // this.setFormValue()
+          });
+        } else {
+          this.resetFields();
+        }
+        this.$listeners.reset();
+      } else {
+        this.resetFields();
+      }
+    },
+    save(search = null, type = "form") {
+      search = search ? search : this.model;
+      this.searchs.update(search, undefined, type);
+    },
+    validate(FC) {
+      this.$refs.form.validate(valid => {
+        FC(valid);
+        if (valid) {
+          this.searchs.update(this.model, undefined, "form");
+        }
+      });
+    },
+    resetFields() {
+      this.$refs.form.resetFields();
+      this.searchs.update(this.model, undefined, "form");
+      this.searchs.update({}, undefined, "page");
+    }
+  }
+};
+</script>
+<style lang="scss" scoped>
+// .save-form {
+//   /deep/ .el-input__inner {
+//     width: 180px;
+//     overflow: hidden;
+//     text-overflow: ellipsis;
+//   }
+//   /deep/.el-select {
+//     width: 100%;
+//   }
+//   /deep/.el-date-editor.el-input {
+//     width: 180px;
+//   }
+//   /deep/ .el-form-item__content .el-col {
+//     width: 180px;
+//   }
+//   /deep/ .el-col.line {
+//     width: 15px !important;
+//     text-align: center;
+//   }
+//   /deep/ .el-date-editor--daterange {
+//     width: 375px;
+//   }
+//   /deep/ .el-form-item__content .el-col:last-child .el-form-item {
+//     margin-right: 0;
+//   }
+// }
+</style>

+ 18 - 0
src/helpers/deep-clone.js

@@ -0,0 +1,18 @@
+// form: https://www.30secondsofcode.org/js/s/deep-clone
+
+const deepClone = obj => {
+  if (obj === null) return null;
+  let clone = Object.assign({}, obj);
+  Object.keys(clone).forEach(
+    key =>
+      (clone[key] =
+        typeof obj[key] === 'object' ? deepClone(obj[key]) : obj[key])
+  );
+  if (Array.isArray(obj)) {
+    clone.length = obj.length;
+    return Array.from(clone);
+  }
+  return clone;
+};
+
+export default deepClone

+ 84 - 0
src/helpers/index.js

@@ -0,0 +1,84 @@
+/* eslint-disable no-empty */
+export class Searchs {
+  saveKey = 'searchs'
+
+  initSearch = {
+    form: {},
+    page: {},
+  }
+
+  searchs = {}
+
+  constructor(key) {
+    this.key = key
+    this.searchs = this.parse()
+  }
+
+  save() {
+    localStorage.setItem(this.saveKey, JSON.stringify(this.searchs))
+  }
+
+  parse() {
+    let json = {...initSearch}
+    try {
+      const val = localStorage.getItem(this.saveKey)
+      json = JSON.parse(val) || json
+    } catch (error) {}
+    return json
+  }
+
+  get(key) {
+    const k = (key || this.key)
+    if (!this.searchs[k]) {
+      this.searchs[k] = {...initSearch}
+    }
+    return this.searchs[k]
+  }
+
+  remove(type) {
+    if (this.searchs && this.searchs[this.key]) {
+      type ? this.searchs[this.key][type] : this.searchs[this.key]
+      this.save()
+    }
+    return this.searchs
+  }
+
+  getSearchs() {
+    return this.searchs
+  }
+
+  removeByKey(key) {
+    delete this.searchs[key]
+    this.save()
+    return this.searchs
+  }
+
+  removeAll() {
+    this.searchs = {}
+    localStorage.setItem(this.saveKey, JSON.stringify(this.searchs))
+    return this.searchs
+  }
+
+  update(data, key, type) {
+    this.searchs = this.parse()
+    const k = (key || this.key)
+    if (!this.searchs[k]) {
+      this.searchs[k] = {...initSearch}
+    }
+
+    if (type) {
+      this.searchs[k][type] = data
+    } else {
+      this.searchs[k] = data
+    }
+    this.save()
+    return this.searchs
+  }
+}
+
+const initSearch = {
+  form: {},
+  page: {},
+}
+
+

+ 194 - 80
src/layout/components/TagsView/index.vue

@@ -5,20 +5,32 @@
         v-for="tag in visitedViews"
         ref="tag"
         :key="tag.path"
-        :class="isActive(tag)?'active':''"
+        :class="isActive(tag) ? 'active' : ''"
         :to="{ path: tag.path, query: tag.query, fullPath: tag.fullPath }"
         tag="span"
         class="tags-view-item"
-        @click.middle.native="!isAffix(tag)?closeSelectedTag(tag):''"
-        @contextmenu.prevent.native="openMenu(tag,$event)"
+        @click.middle.native="!isAffix(tag) ? closeSelectedTag(tag) : ''"
+        @contextmenu.prevent.native="openMenu(tag, $event)"
       >
-        {{ tag.title }}
-        <span v-if="!isAffix(tag)" class="el-icon-close" @click.prevent.stop="closeSelectedTag(tag)" />
+        <span :title="tag.title" class="item" @click="changeTag(tag)">{{
+          tag.title
+        }}</span>
+        <span
+          v-if="!isAffix(tag)"
+          class="el-icon-close"
+          @click.prevent.stop="closeSelectedTag(tag)"
+        ></span>
       </router-link>
     </scroll-pane>
-    <ul v-show="visible" :style="{left:left+'px',top:top+'px'}" class="contextmenu">
+    <ul
+      v-show="visible"
+      :style="{ left: left + 'px', top: top + 'px' }"
+      class="contextmenu"
+    >
       <li @click="refreshSelectedTag(selectedTag)">刷新</li>
-      <li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)">关闭</li>
+      <li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)">
+        关闭
+      </li>
       <li @click="closeOthersTags">关闭其它</li>
       <li @click="closeAllTags(selectedTag)">关闭所有</li>
     </ul>
@@ -26,9 +38,10 @@
 </template>
 
 <script>
-import ScrollPane from './ScrollPane'
-import path from 'path'
-
+import ScrollPane from "./ScrollPane";
+import path from "path";
+import { Searchs } from "@/helpers";
+let activeKey = "";
 export default {
   components: { ScrollPane },
   data() {
@@ -38,160 +51,261 @@ export default {
       left: 0,
       selectedTag: {},
       affixTags: []
-    }
+    };
   },
   computed: {
     visitedViews() {
-      return this.$store.state.tagsView.visitedViews
+      return this.$store.state.tagsView.visitedViews;
     },
     routes() {
-      return this.$store.state.permission.routes
+      return this.$store.state.permission.routes;
     }
   },
   watch: {
     $route() {
-      this.addTags()
-      this.moveToCurrentTag()
+      this.addTags();
+      this.moveToCurrentTag();
+
+      // 就是为了处理,tab 切换,saveKey 问题
+      console.log(activeKey, this.$store.state);
+      if (!activeKey && !this.$store.state.tagsView.isBack) {
+        const s = new Searchs();
+        const keys = [this.$route.path];
+        for (const key in s.searchs) {
+          if (Object.hasOwnProperty.call(s.searchs, key)) {
+            const item = s.searchs[key];
+            if (item.bind === this.$route.path && item.bind !== "/workbench") {
+              keys.push(key);
+            }
+          }
+        }
+        // 当点击侧边栏的时候需要刷新页面 所以得把当前路由缓存得数据清理掉
+        for (const item of keys) {
+          s.removeByKey(item);
+        }
+      }
+      // this.$store.commit("SET_IS_BACK", false);
+      this.$store.dispatch("tagsView/setBackStatus", false);
+      activeKey = "";
     },
     visible(value) {
       if (value) {
-        document.body.addEventListener('click', this.closeMenu)
+        document.body.addEventListener("click", this.closeMenu);
       } else {
-        document.body.removeEventListener('click', this.closeMenu)
+        document.body.removeEventListener("click", this.closeMenu);
       }
+    },
+    async "$route.meta.title"(val) {
+      await this.$store.dispatch("tagsView/addVisitedView", this.$route);
     }
   },
   mounted() {
-    this.initTags()
-    this.addTags()
+    this.initTags();
+    this.addTags();
   },
   methods: {
     isActive(route) {
-      return route.path === this.$route.path
+      return route.path === this.$route.path;
     },
     isAffix(tag) {
-      return tag.meta && tag.meta.affix
+      return tag.meta && tag.meta.affix;
     },
-    filterAffixTags(routes, basePath = '/') {
-      let tags = []
+    filterAffixTags(routes, basePath = "/") {
+      let tags = [];
       routes.forEach(route => {
         if (route.meta && route.meta.affix) {
-          const tagPath = path.resolve(basePath, route.path)
+          const tagPath = path.resolve(basePath, route.path);
           tags.push({
             fullPath: tagPath,
             path: tagPath,
             name: route.name,
             meta: { ...route.meta }
-          })
+          });
         }
         if (route.children) {
-          const tempTags = this.filterAffixTags(route.children, route.path)
+          const tempTags = this.filterAffixTags(route.children, route.path);
           if (tempTags.length >= 1) {
-            tags = [...tags, ...tempTags]
+            tags = [...tags, ...tempTags];
           }
         }
-      })
-      return tags
+      });
+      return tags;
     },
     initTags() {
-      const affixTags = this.affixTags = this.filterAffixTags(this.routes)
+      const affixTags = (this.affixTags = this.filterAffixTags(this.routes));
       for (const tag of affixTags) {
         // Must have tag name
         if (tag.name) {
-          this.$store.dispatch('tagsView/addVisitedView', tag)
+          this.$store.dispatch("tagsView/addVisitedView", tag);
+        }
+      }
+    },
+    async changeTag(tag) {
+      activeKey = await this.getSearchsByRealPath(tag);
+    },
+    getSearchsByRealPath(tag) {
+      const searchs = new Searchs();
+      let keyName = "";
+
+      for (const key in searchs.searchs) {
+        if (Object.hasOwnProperty.call(searchs.searchs, key)) {
+          const item = searchs.searchs[key];
+
+          if (tag.path === key || item.bind === tag.path) {
+            keyName = item.bind || tag.path;
+          }
+        }
+      }
+      // this.activeKey = keyName
+      return keyName;
+    },
+    syncTagViewAndSaveForm() {
+      const keys = this.$store.state.tagsView.visitedViews.map(item => {
+        //  (item)
+        return item.path;
+      });
+      const searchs = new Searchs();
+      const allSearch = searchs.getSearchs();
+
+      const sks = Object.keys(allSearch);
+      let route = this.$route;
+      for (const item of sks) {
+        if (!(keys.includes(item) || keys.includes(allSearch[item].bind))) {
+          searchs.removeByKey(item);
+        }
+
+        let tempSaveKeyList = item.split("|");
+        // 大于1说明的特殊标识编号
+        if (tempSaveKeyList.length > 1) {
+          if (
+            allSearch[item] &&
+            route.path == allSearch[item].bind &&
+            route.query[tempSaveKeyList[1]] != tempSaveKeyList[2]
+          ) {
+            searchs.removeByKey(item);
+          }
         }
       }
     },
     addTags() {
-      const { name } = this.$route
+      const { name } = this.$route;
       if (name) {
-        this.$store.dispatch('tagsView/addView', this.$route)
+        this.$store.dispatch("tagsView/addView", this.$route);
+
+        // this.syncTagViewAndSaveForm();
       }
-      return false
+      return false;
     },
     moveToCurrentTag() {
-      const tags = this.$refs.tag
+      const tags = this.$refs.tag;
       this.$nextTick(() => {
         for (const tag of tags) {
           if (tag.to.path === this.$route.path) {
-            this.$refs.scrollPane.moveToTarget(tag)
+            this.$refs.scrollPane.moveToTarget(tag);
             // when query is different then update
             if (tag.to.fullPath !== this.$route.fullPath) {
-              this.$store.dispatch('tagsView/updateVisitedView', this.$route)
+              this.$store.dispatch("tagsView/updateVisitedView", this.$route);
             }
-            break
+            break;
           }
         }
-      })
+      });
     },
     refreshSelectedTag(view) {
-      this.$store.dispatch('tagsView/delCachedView', view).then(() => {
-        const { fullPath } = view
+      this.$store.dispatch("tagsView/delCachedView", view).then(() => {
+        const { fullPath } = view;
         this.$nextTick(() => {
           this.$router.replace({
-            path: '/redirect' + fullPath
-          })
-        })
-      })
+            path: "/redirect" + fullPath
+          });
+        });
+      });
     },
     closeSelectedTag(view) {
-      this.$store.dispatch('tagsView/delView', view).then(({ visitedViews }) => {
-        if (this.isActive(view)) {
-          this.toLastView(visitedViews, view)
-        }
-      })
+      const searchs = new Searchs();
+      searchs.remove(this.$route.path);
+      // this.$store
+      //   .dispatch("delVisitedViews", { ...view, dontNeedSave: true })
+      //   .then(views => {
+      //     if (this.isActive(view)) {
+      //       const latestView = views.slice(-1)[0];
+      //       if (latestView) {
+      //         this.$router.push(latestView.fullPath);
+      //       } else {
+      //         let firstMenuUrl = localStorage.getItem("firstMenuUrl");
+      //         this.$router.push(firstMenuUrl || "/");
+      //       }
+      //     }
+      //   });
+      this.$store
+        .dispatch("tagsView/delView", view)
+        .then(({ visitedViews }) => {
+          if (this.isActive(view)) {
+            this.toLastView(visitedViews, view);
+
+            const latestView = visitedViews.slice(-1)[0];
+            if (latestView) {
+              this.$router.push(latestView.fullPath);
+            } else {
+              let firstMenuUrl = localStorage.getItem("firstMenuUrl");
+              this.$router.push(firstMenuUrl || "/");
+            }
+          }
+        });
     },
     closeOthersTags() {
-      this.$router.push(this.selectedTag)
-      this.$store.dispatch('tagsView/delOthersViews', this.selectedTag).then(() => {
-        this.moveToCurrentTag()
-      })
+      this.$router.push(this.selectedTag);
+      this.$store
+        .dispatch("tagsView/delOthersViews", this.selectedTag)
+        .then(() => {
+          this.moveToCurrentTag();
+        });
     },
     closeAllTags(view) {
-      this.$store.dispatch('tagsView/delAllViews').then(({ visitedViews }) => {
+      this.$store.dispatch("tagsView/delAllViews").then(({ visitedViews }) => {
         if (this.affixTags.some(tag => tag.path === view.path)) {
-          return
+          return;
         }
-        this.toLastView(visitedViews, view)
-      })
+        this.toLastView(visitedViews, view);
+      });
     },
     toLastView(visitedViews, view) {
-      const latestView = visitedViews.slice(-1)[0]
+      const latestView = visitedViews.slice(-1)[0];
       if (latestView) {
-        this.$router.push(latestView.fullPath)
+        this.$router.push(latestView.fullPath);
       } else {
         // now the default is to redirect to the home page if there is no tags-view,
         // you can adjust it according to your needs.
-        if (view.name === 'Dashboard') {
+        if (view.name === "Dashboard") {
           // to reload home page
-          this.$router.replace({ path: '/redirect' + view.fullPath })
+          this.$router.replace({ path: "/redirect" + view.fullPath });
         } else {
-          this.$router.push('/')
+          this.$router.push("/");
         }
       }
     },
     openMenu(tag, e) {
-      const menuMinWidth = 105
-      const offsetLeft = this.$el.getBoundingClientRect().left // container margin left
-      const offsetWidth = this.$el.offsetWidth // container width
-      const maxLeft = offsetWidth - menuMinWidth // left boundary
-      const left = e.clientX - offsetLeft + 15 // 15: margin right
+      const menuMinWidth = 105;
+      const offsetLeft = this.$el.getBoundingClientRect().left; // container margin left
+      const offsetWidth = this.$el.offsetWidth; // container width
+      const maxLeft = offsetWidth - menuMinWidth; // left boundary
+      const left = e.clientX - offsetLeft + 15; // 15: margin right
 
       if (left > maxLeft) {
-        this.left = maxLeft
+        this.left = maxLeft;
       } else {
-        this.left = left
+        this.left = left;
       }
 
-      this.top = e.clientY
-      this.visible = true
-      this.selectedTag = tag
+      this.top = e.clientY;
+      this.visible = true;
+      this.selectedTag = tag;
     },
     closeMenu() {
-      this.visible = false
+      this.visible = false;
     }
   }
-}
+};
 </script>
 
 <style lang="scss" scoped>
@@ -200,7 +314,7 @@ export default {
   width: 100%;
   background: #fff;
   border-bottom: 1px solid #d8dce5;
-  box-shadow: 0 1px 3px 0 rgba(0, 0, 0, .12), 0 0 3px 0 rgba(0, 0, 0, .04);
+  box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12), 0 0 3px 0 rgba(0, 0, 0, 0.04);
   .tags-view-wrapper {
     .tags-view-item {
       display: inline-block;
@@ -226,7 +340,7 @@ export default {
         color: #fff;
         border-color: #42b983;
         &::before {
-          content: '';
+          content: "";
           background: #fff;
           display: inline-block;
           width: 8px;
@@ -249,7 +363,7 @@ export default {
     font-size: 12px;
     font-weight: 400;
     color: #333;
-    box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, .3);
+    box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, 0.3);
     li {
       margin: 0;
       padding: 7px 16px;
@@ -272,10 +386,10 @@ export default {
       vertical-align: 2px;
       border-radius: 50%;
       text-align: center;
-      transition: all .3s cubic-bezier(.645, .045, .355, 1);
+      transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
       transform-origin: 100% 50%;
       &:before {
-        transform: scale(.6);
+        transform: scale(0.6);
         display: inline-block;
         vertical-align: -3px;
       }

+ 7 - 0
src/store/modules/tagsView.js

@@ -63,6 +63,9 @@ const mutations = {
         break
       }
     }
+  },
+  SET_IS_BACK: (state, isBack) => {
+    state.isBack = isBack
   }
 }
 
@@ -90,6 +93,7 @@ const actions = {
   },
   delVisitedView({ commit, state }, view) {
     return new Promise(resolve => {
+      commit('SET_IS_BACK', !view.dontNeedSave)
       commit('DEL_VISITED_VIEW', view)
       resolve([...state.visitedViews])
     })
@@ -149,6 +153,9 @@ const actions = {
 
   updateVisitedView({ commit }, view) {
     commit('UPDATE_VISITED_VIEW', view)
+  },
+  setBackStatus({ commit }, view) {
+    commit('SET_IS_BACK', view)
   }
 }
 

+ 1 - 1
src/utils/auth.js

@@ -25,7 +25,7 @@ function getKeyWordKey() {
 }
 
 export function getToken() {
-  console.log(location.origin, TokenKey)
+  // console.log(location.origin, TokenKey)
   if (!(ip.test(host) === true) && !host === 'localhost') {
     Cookies.remove('dy_admin_token')
   }

+ 1 - 1
src/utils/costum.js

@@ -103,6 +103,6 @@ export function initNumberHtml(val) {
       document.querySelector('#addSpan').innerHTML = val
     }
   } else {
-    document.querySelector('#addSpan').remove()
+    document.querySelector('#addSpan') && document.querySelector('#addSpan').remove()
   }
 }

+ 158 - 136
src/views/login/index.vue

@@ -23,13 +23,20 @@
     <div class="login-weaper animated bounceInDown">
       <div class="login-left">
         <div class="login-time" v-text="currentTime" />
-        <img :src="logo" alt="" class="img">
+        <img :src="logo" alt="" class="img" />
         <p class="title" v-text="title" />
       </div>
       <div class="login-border">
         <div class="login-main">
-          <div class="login-title"> 用户登录 </div>
-          <el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form" autocomplete="on" label-position="left">
+          <div class="login-title">用户登录</div>
+          <el-form
+            ref="loginForm"
+            :model="loginForm"
+            :rules="loginRules"
+            class="login-form"
+            autocomplete="on"
+            label-position="left"
+          >
             <el-form-item prop="username">
               <span class="svg-container">
                 <i class="el-icon-user" />
@@ -45,7 +52,12 @@
               />
             </el-form-item>
 
-            <el-tooltip v-model="capsTooltip" content="Caps lock is On" placement="right" manual>
+            <el-tooltip
+              v-model="capsTooltip"
+              content="Caps lock is On"
+              placement="right"
+              manual
+            >
               <el-form-item prop="password">
                 <span class="svg-container">
                   <svg-icon icon-class="password" />
@@ -64,7 +76,11 @@
                   @keyup.enter.native="handleLogin"
                 />
                 <span class="show-pwd" @click="showPwd">
-                  <svg-icon :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'" />
+                  <svg-icon
+                    :icon-class="
+                      passwordType === 'password' ? 'eye' : 'eye-open'
+                    "
+                  />
                 </span>
               </el-form-item>
             </el-tooltip>
@@ -91,79 +107,82 @@
             <!-- <div prop="code" style="width: 100%;float: left;margin-bottom: 13px">
               <el-checkbox v-model="isLdap">LDAP登陆</el-checkbox>
             </div> -->
-            <el-button :loading="loading" type="primary" style="width:100%;padding:12px 20px;margin-bottom:30px;" @click.native.prevent="handleLogin">
+            <el-button
+              :loading="loading"
+              type="primary"
+              style="width:100%;padding:12px 20px;margin-bottom:30px;"
+              @click.native.prevent="handleLogin"
+            >
               <span v-if="!loading">登 录</span>
               <span v-else>登 录 中...</span>
             </el-button>
           </el-form>
         </div>
       </div>
-
     </div>
   </div>
 </template>
 
 <script>
-
-import { getCodeImg } from '@/api/login'
-import moment from 'moment'
-import { mapGetters } from 'vuex'
+import { getCodeImg } from "@/api/login";
+import moment from "moment";
+import { mapGetters } from "vuex";
 
 export default {
-  name: 'Login',
+  name: "Login",
   data() {
     const validateUsername = (rule, value, callback) => {
       // validUsername
       if (!value) {
-        callback(new Error('请输入用户名'))
+        callback(new Error("请输入用户名"));
       } else {
-        callback()
+        callback();
       }
-    }
+    };
     const validatePassword = (rule, value, callback) => {
       if (value.length < 6) {
-        callback(new Error('密码必须大于六位'))
+        callback(new Error("密码必须大于六位"));
       } else {
-        callback()
+        callback();
       }
-    }
+    };
     return {
-      codeUrl: '',
-      cookiePassword: '',
+      codeUrl: "",
+      cookiePassword: "",
       loginForm: {
-        username: '',
-        password: '',
+        username: "",
+        password: "",
         rememberMe: false,
-        code: '',
-        uuid: '',
+        code: "",
+        uuid: "",
         loginType: 1
       },
       loginRules: {
         username: [
-          { required: true, trigger: 'blur', validator: validateUsername }
+          { required: true, trigger: "blur", validator: validateUsername }
         ],
         password: [
-          { required: true, trigger: 'blur', validator: validatePassword }
+          { required: true, trigger: "blur", validator: validatePassword }
         ]
       },
-      passwordType: 'password',
+      passwordType: "password",
       capsTooltip: false,
       loading: false,
       redirect: undefined,
       otherQuery: {},
       currentTime: null
-    }
+    };
   },
   computed: {
-    ...mapGetters(['title', 'logo', 'isLdap'])
+    ...mapGetters(["title", "logo", "isLdap"])
   },
   watch: {
     $route: {
       handler: function(route) {
-        const query = route.query
+        const query = route.query;
         if (query) {
-          this.redirect = query.redirect
-          this.otherQuery = this.getOtherQuery(query)
+          this.redirect = query.redirect;
+          this.otherQuery = this.getOtherQuery(query);
         }
       },
       immediate: true
@@ -172,134 +191,138 @@ export default {
   created() {
     // this.getCode()
     // window.addEventListener('storage', this.afterQRScan)
-    this.getCurrentTime()
+    this.getCurrentTime();
   },
   mounted() {
-    if (this.loginForm.username === '') {
-      this.$refs.username.focus()
-    } else if (this.loginForm.password === '') {
-      this.$refs.password.focus()
+    if (this.loginForm.username === "") {
+      this.$refs.username.focus();
+    } else if (this.loginForm.password === "") {
+      this.$refs.password.focus();
     }
   },
   destroyed() {
-    clearInterval(this.timer)
+    clearInterval(this.timer);
     // window.removeEventListener('storage', this.afterQRScan)
   },
   methods: {
     getCurrentTime() {
       this.timer = setInterval(_ => {
-        this.currentTime = moment().format('YYYY-MM-DD HH时mm分ss秒')
-      }, 1000)
+        this.currentTime = moment().format("YYYY-MM-DD HH时mm分ss秒");
+      }, 1000);
     },
     getCode() {
       getCodeImg().then(res => {
         if (res !== undefined) {
-          this.codeUrl = res.data
-          this.loginForm.uuid = res.id
+          this.codeUrl = res.data;
+          this.loginForm.uuid = res.id;
         }
-      })
+      });
     },
     checkCapslock({ shiftKey, key } = {}) {
       if (key && key.length === 1) {
-        if (shiftKey && (key >= 'a' && key <= 'z') || !shiftKey && (key >= 'A' && key <= 'Z')) {
-          this.capsTooltip = true
+        if (
+          (shiftKey && key >= "a" && key <= "z") ||
+          (!shiftKey && key >= "A" && key <= "Z")
+        ) {
+          this.capsTooltip = true;
         } else {
-          this.capsTooltip = false
+          this.capsTooltip = false;
         }
       }
-      if (key === 'CapsLock' && this.capsTooltip === true) {
-        this.capsTooltip = false
+      if (key === "CapsLock" && this.capsTooltip === true) {
+        this.capsTooltip = false;
       }
     },
     showPwd() {
-      if (this.passwordType === 'password') {
-        this.passwordType = ''
+      if (this.passwordType === "password") {
+        this.passwordType = "";
       } else {
-        this.passwordType = 'password'
+        this.passwordType = "password";
       }
       this.$nextTick(() => {
-        this.$refs.password.focus()
-      })
+        this.$refs.password.focus();
+      });
     },
     handleLogin() {
       this.$refs.loginForm.validate(valid => {
         if (valid) {
           if (this.isLdap) {
-            this.loginForm.loginType = 1
+            this.loginForm.loginType = 1;
           } else {
-            this.loginForm.loginType = 0
+            this.loginForm.loginType = 0;
           }
-
-          this.loading = true
-          this.$store.dispatch('user/login', this.loginForm)
+          localStorage.removeItem("searchs");
+          this.loading = true;
+          this.$store
+            .dispatch("user/login", this.loginForm)
             .then(() => {
               // this.$router.push({ path: this.redirect || '/', query: this.otherQuery })
-              this.$router.push({ path: '/' })
-              this.loading = false
+              this.$router.push({ path: "/" });
+              this.loading = false;
             })
             .catch(() => {
-              this.loading = false
+              this.loading = false;
               // this.getCode()
-            })
+            });
         } else {
-          return false
+          return false;
         }
-      })
+      });
     },
     getOtherQuery(query) {
       return Object.keys(query).reduce((acc, cur) => {
-        if (cur !== 'redirect') {
-          acc[cur] = query[cur]
+        if (cur !== "redirect") {
+          acc[cur] = query[cur];
         }
-        return acc
-      }, {})
+        return acc;
+      }, {});
     }
   }
-}
+};
 </script>
 
 <style lang="scss" scoped>
 /* 修复input 背景不协调 和光标变色 */
 /* Detail see https://github.com/PanJiaChen/vue-element-admin/pull/927 */
 
-$bg:#283443;
-$light_gray:#fff;
+$bg: #283443;
+$light_gray: #fff;
 $cursor: #fff;
 
-.login-container{
-    display: -webkit-box;
-    display: -ms-flexbox;
-    display: flex;
-    -webkit-box-align: center;
-    -ms-flex-align: center;
-    align-items: center;
-    width: 100%;
-    height: 100%;
-    margin: 0 auto;
-    background: url("../../assets/login.png") no-repeat;
-    background-color: #304175;
-    position: relative;
-    background-size: cover;
-    height: 100vh;
-    background-position: 50%;
+.login-container {
+  display: -webkit-box;
+  display: -ms-flexbox;
+  display: flex;
+  -webkit-box-align: center;
+  -ms-flex-align: center;
+  align-items: center;
+  width: 100%;
+  height: 100%;
+  margin: 0 auto;
+  background: url("../../assets/login.png") no-repeat;
+  background-color: #304175;
+  position: relative;
+  background-size: cover;
+  height: 100vh;
+  background-position: 50%;
 }
 
-#particles-js{
-    z-index: 1;
-    width: 100%;
-    height: 100%;
-    position: absolute;
+#particles-js {
+  z-index: 1;
+  width: 100%;
+  height: 100%;
+  position: absolute;
 }
 
-.login-weaper{
+.login-weaper {
   margin: 0 auto;
   width: 1000px;
-  -webkit-box-shadow: -4px 5px 10px rgba(0,0,0,.4);
-  box-shadow: -4px 5px 10px rgba(0,0,0,.4);
+  -webkit-box-shadow: -4px 5px 10px rgba(0, 0, 0, 0.4);
+  box-shadow: -4px 5px 10px rgba(0, 0, 0, 0.4);
   z-index: 1000;
 }
 
-.login-left{
+.login-left {
   border-top-left-radius: 5px;
   border-bottom-left-radius: 5px;
   -webkit-box-pack: center;
@@ -309,32 +332,32 @@ $cursor: #fff;
   -webkit-box-direction: normal;
   -ms-flex-direction: column;
   flex-direction: column;
-  background-color: rgba(64,158,255,0);
+  background-color: rgba(64, 158, 255, 0);
   color: #fff;
   float: left;
   width: 50%;
   position: relative;
-    min-height: 500px;
-    -webkit-box-align: center;
-    -ms-flex-align: center;
-    align-items: center;
-    display: -webkit-box;
-    display: -ms-flexbox;
-    display: flex;
-  .login-time{
+  min-height: 500px;
+  -webkit-box-align: center;
+  -ms-flex-align: center;
+  align-items: center;
+  display: -webkit-box;
+  display: -ms-flexbox;
+  display: flex;
+  .login-time {
     position: absolute;
     left: 25px;
     top: 25px;
     width: 100%;
     color: #fff;
-    opacity: .9;
+    opacity: 0.9;
     font-size: 18px;
     overflow: hidden;
     font-weight: 500;
   }
 }
 
-.login-left .img{
+.login-left .img {
   width: 120px;
   height: 120px;
   border-radius: 3px;
@@ -348,36 +371,36 @@ $cursor: #fff;
   font-weight: 600;
 }
 
-.login-border{
+.login-border {
   position: relative;
-    min-height: 500px;
-    -webkit-box-align: center;
-    -ms-flex-align: center;
-    align-items: center;
-    display: -webkit-box;
-    display: -ms-flexbox;
-    display: flex;
-    border-left: none;
-    border-top-right-radius: 5px;
-    border-bottom-right-radius: 5px;
-    color: #fff;
-    background-color: hsla(0,0%,100%,.9);
-    width: 50%;
-    float: left;
+  min-height: 500px;
+  -webkit-box-align: center;
+  -ms-flex-align: center;
+  align-items: center;
+  display: -webkit-box;
+  display: -ms-flexbox;
+  display: flex;
+  border-left: none;
+  border-top-right-radius: 5px;
+  border-bottom-right-radius: 5px;
+  color: #fff;
+  background-color: hsla(0, 0%, 100%, 0.9);
+  width: 50%;
+  float: left;
 }
 
-.login-main{
-    margin: 0 auto;
-    width: 65%;
+.login-main {
+  margin: 0 auto;
+  width: 65%;
 }
 
-.login-title{
+.login-title {
   color: #333;
-    margin-bottom: 40px;
-    font-weight: 500;
-    font-size: 22px;
-    text-align: center;
-    letter-spacing: 4px;
+  margin-bottom: 40px;
+  font-weight: 500;
+  font-size: 22px;
+  text-align: center;
+  letter-spacing: 4px;
 }
 
 @supports (-webkit-mask: none) and (not (cater-color: $cursor)) {
@@ -411,18 +434,17 @@ $cursor: #fff;
   }
 
   .el-form-item {
-    border: 1px solid rgba(0,0,0, 0.1);
+    border: 1px solid rgba(0, 0, 0, 0.1);
     background: rgba(255, 255, 255, 0.8);
     border-radius: 5px;
     color: #454545;
   }
 }
-$bg:#2d3a4b;
-$dark_gray:#889aa4;
-$light_gray:#eee;
+$bg: #2d3a4b;
+$dark_gray: #889aa4;
+$light_gray: #eee;
 
 .login-container {
-
   .tips {
     font-size: 14px;
     color: #fff;

+ 140 - 83
src/views/process/admin/classify.vue

@@ -1,7 +1,12 @@
 <template>
   <div class="app-container">
     <el-card class="box-card">
-      <el-form ref="listQuery" :model="listQuery" :inline="true">
+      <save-form
+        ref="listQuery"
+        :model="listQuery"
+        @submit="handleQuery"
+        :inline="true"
+      >
         <el-form-item label="分类名称">
           <el-input
             v-model="listQuery.name"
@@ -13,9 +18,15 @@
           />
         </el-form-item>
         <el-form-item>
-          <el-button type="primary" icon="el-icon-search" size="small" @click="handleQuery">搜索</el-button>
+          <el-button
+            type="primary"
+            icon="el-icon-search"
+            size="small"
+            native-type="submit"
+            >搜索</el-button
+          >
         </el-form-item>
-      </el-form>
+      </save-form>
 
       <el-row :gutter="10" class="mb8">
         <el-col :span="1.5">
@@ -25,7 +36,8 @@
             icon="el-icon-plus"
             size="mini"
             @click="handleCreate"
-          >新增</el-button>
+            >新增</el-button
+          >
         </el-col>
         <!-- <el-col :span="1.5">
           <el-button
@@ -49,17 +61,40 @@
         </el-col> -->
       </el-row>
 
-      <el-table v-loading="loading" border :data="classifyList" @selection-change="handleSelectionChange">
+      <el-table
+        v-loading="loading"
+        border
+        :data="classifyList"
+        @selection-change="handleSelectionChange"
+      >
         <el-table-column type="selection" width="55" align="center" />
         <el-table-column label="ID" prop="id" width="120" />
-        <el-table-column label="名称" prop="name" :show-overflow-tooltip="true" />
-        <el-table-column label="创建者" prop="create_name" :show-overflow-tooltip="true" width="150" />
-        <el-table-column label="创建时间" align="center" prop="create_time" width="180">
+        <el-table-column
+          label="名称"
+          prop="name"
+          :show-overflow-tooltip="true"
+        />
+        <el-table-column
+          label="创建者"
+          prop="create_name"
+          :show-overflow-tooltip="true"
+          width="150"
+        />
+        <el-table-column
+          label="创建时间"
+          align="center"
+          prop="create_time"
+          width="180"
+        >
           <template slot-scope="scope">
             <span>{{ parseTime(scope.row.create_time) }}</span>
           </template>
         </el-table-column>
-        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <el-table-column
+          label="操作"
+          align="center"
+          class-name="small-padding fixed-width"
+        >
           <template slot-scope="scope">
             <el-button
               v-permisaction="['process:admin:classify:edit']"
@@ -67,35 +102,54 @@
               type="text"
               icon="el-icon-edit"
               @click="handleEdit(scope.row)"
-            >编辑</el-button>
+              >编辑</el-button
+            >
             <el-button
               v-permisaction="['process:admin:classify:delete']"
               size="mini"
               type="text"
               icon="el-icon-delete"
               @click="handleDelete(scope.row)"
-            >删除</el-button>
+              >删除</el-button
+            >
           </template>
         </el-table-column>
       </el-table>
 
       <pagination
-        v-show="total>0"
+        v-show="total > 0"
         :total="total"
         :page.sync="queryParams.pageIndex"
         :limit.sync="queryParams.pageSize"
         @pagination="getList"
       />
 
-      <el-dialog :title="dialogFormVisibleName===1?'新建分类':'编辑分类'" :visible.sync="open" width="600px">
+      <el-dialog
+        :title="dialogFormVisibleName === 1 ? '新建分类' : '编辑分类'"
+        :visible.sync="open"
+        width="600px"
+      >
         <div class="tpl-create-content">
-          <el-form ref="ruleForm" :model="ruleForm" :rules="rules" label-width="100px">
+          <el-form
+            ref="ruleForm"
+            :model="ruleForm"
+            :rules="rules"
+            label-width="100px"
+          >
             <el-form-item label="分类名称" prop="name" style="width: 95%">
               <el-input v-model="ruleForm.name" />
             </el-form-item>
           </el-form>
           <div slot="footer" class="dialog-footer" style="text-align: right">
-            <el-button type="primary" @click="dialogFormVisibleName===1?submitForm('ruleForm'):editForm('ruleForm')">提交</el-button>
+            <el-button
+              type="primary"
+              @click="
+                dialogFormVisibleName === 1
+                  ? submitForm('ruleForm')
+                  : editForm('ruleForm')
+              "
+              >提交</el-button
+            >
             <el-button @click="open = false">取 消</el-button>
           </div>
         </div>
@@ -110,10 +164,13 @@ import {
   classifyList,
   updateClassify,
   deleteClassify
-} from '@/api/process/admin/classify'
-
+} from "@/api/process/admin/classify";
+import SaveForm from "@/components/save-form";
 export default {
-  name: 'Classify',
+  name: "Classify",
+  components: {
+    SaveForm
+  },
   data() {
     return {
       dialogFormVisibleName: 1,
@@ -138,108 +195,108 @@ export default {
       },
       ruleForm: {
         id: undefined,
-        name: ''
+        name: ""
       },
       rules: {
-        name: [
-          { required: true, message: '请输入流程分类', trigger: 'blur' }
-        ]
+        name: [{ required: true, message: "请输入流程分类", trigger: "blur" }]
       }
-    }
+    };
   },
-  created() {
-    this.getList()
+  mounted() {
+    this.getList();
   },
   methods: {
     /** 查询角色列表 */
     getList() {
-      this.loading = true
-      this.listQuery.page = this.queryParams.pageIndex
-      this.listQuery.per_page = this.queryParams.pageSize
+      this.loading = true;
+      this.listQuery.page = this.queryParams.pageIndex;
+      this.listQuery.per_page = this.queryParams.pageSize;
       classifyList(this.listQuery).then(response => {
-        this.classifyList = response.data.data
-        this.queryParams.pageIndex = response.data.page
-        this.queryParams.pageSize = response.data.per_page
-        this.total = response.data.total_count
-        this.loading = false
-      })
+        this.classifyList = response.data.data;
+        this.queryParams.pageIndex = response.data.page;
+        this.queryParams.pageSize = response.data.per_page;
+        this.total = response.data.total_count;
+        this.loading = false;
+      });
     },
     handleCreate() {
       this.ruleForm = {
         id: undefined,
-        name: ''
-      }
-      this.dialogFormVisibleName = 1
-      this.open = true
+        name: ""
+      };
+      this.dialogFormVisibleName = 1;
+      this.open = true;
     },
     handleEdit(row) {
-      this.dialogFormVisibleName = 2
-      this.ruleForm.id = row.id
-      this.ruleForm.name = row.name
-      this.open = true
+      this.dialogFormVisibleName = 2;
+      this.ruleForm.id = row.id;
+      this.ruleForm.name = row.name;
+      this.open = true;
     },
     submitForm(formName) {
-      this.$refs[formName].validate((valid) => {
+      this.$refs[formName].validate(valid => {
         if (valid) {
           createClassify(this.ruleForm).then(response => {
             if (response !== undefined) {
-              this.getList()
+              this.getList();
               this.$message({
-                type: 'success',
-                message: '分类已增加!'
-              })
-              this.open = false
+                type: "success",
+                message: "分类已增加!"
+              });
+              this.open = false;
             }
-          })
+          });
         }
-      })
+      });
     },
     editForm(formName) {
-      this.$refs[formName].validate((valid) => {
+      this.$refs[formName].validate(valid => {
         if (valid) {
           updateClassify(this.ruleForm).then(response => {
             if (response !== undefined) {
-              this.getList()
+              this.getList();
               this.$message({
-                type: 'success',
-                message: '分类已更新!'
-              })
-              this.open = false
+                type: "success",
+                message: "分类已更新!"
+              });
+              this.open = false;
             }
-          })
+          });
         }
-      })
+      });
     },
     handleQuery() {
-      this.queryParams.pageIndex = 1
-      this.queryParams.pageSize = 10
-      this.getList()
+      this.queryParams.pageIndex = 1;
+      this.queryParams.pageSize = 10;
+      this.getList();
     },
     handleDelete(row) {
-      this.$confirm('此操作将永久删除该数据, 是否继续?', '提示', {
-        confirmButtonText: '确定',
-        cancelButtonText: '取消',
-        type: 'warning'
-      }).then(() => {
-        deleteClassify({
-          classifyId: row.id
-        }).then(response => {
-          if (response !== undefined) {
-            this.getList()
-            this.$message({
-              type: 'success',
-              message: '分类已删除!'
-            })
-          }
-        })
-      }).catch(() => {
-        this.$message({
-          type: 'info',
-          message: '已取消删除'
-        })
+      this.$confirm("此操作将永久删除该数据, 是否继续?", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
       })
+        .then(() => {
+          deleteClassify({
+            classifyId: row.id
+          }).then(response => {
+            if (response !== undefined) {
+              this.getList();
+              this.$message({
+                type: "success",
+                message: "分类已删除!"
+              });
+            }
+          });
+        })
+        .catch(() => {
+          this.$message({
+            type: "info",
+            message: "已取消删除"
+          });
+        });
     },
     handleSelectionChange() {}
   }
-}
+};
 </script>

+ 352 - 237
src/views/process/admin/process-manager.vue

@@ -1,7 +1,12 @@
 <template>
   <div class="app-container">
     <el-card class="box-card">
-      <el-form ref="listQuery" :model="listQuery" :inline="true">
+      <save-form
+        ref="listQuery"
+        :model="listQuery"
+        :inline="true"
+        @submit="handleQuery"
+      >
         <el-form-item label="流程名称">
           <el-input
             v-model="listQuery.name"
@@ -13,9 +18,15 @@
           />
         </el-form-item>
         <el-form-item>
-          <el-button type="primary" icon="el-icon-search" size="small" @click="handleQuery">搜索</el-button>
+          <el-button
+            type="primary"
+            icon="el-icon-search"
+            size="small"
+            native-type="submit"
+            >搜索</el-button
+          >
         </el-form-item>
-      </el-form>
+      </save-form>
 
       <el-row :gutter="10" class="mb8">
         <el-col :span="1.5">
@@ -25,7 +36,8 @@
             icon="el-icon-plus"
             size="mini"
             @click="handleCreate"
-          >新增</el-button>
+            >新增</el-button
+          >
         </el-col>
         <!-- <el-col :span="1.5">
           <el-button
@@ -49,14 +61,42 @@
         </el-col> -->
       </el-row>
 
-      <el-table v-loading="loading" border :data="processValueList" @selection-change="handleSelectionChange">
+      <el-table
+        v-loading="loading"
+        border
+        :data="processValueList"
+        @selection-change="handleSelectionChange"
+      >
         <el-table-column type="selection" width="55" align="center" />
         <el-table-column label="ID" prop="id" width="120" />
-        <el-table-column label="名称" prop="name" :show-overflow-tooltip="true" />
-        <el-table-column label="创建者" prop="create_name" :show-overflow-tooltip="true" width="150" />
-        <el-table-column label="创建时间" align="center" prop="create_time" width="180" />
-        <el-table-column label="更新时间" align="center" prop="update_time" width="180" />
-        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <el-table-column
+          label="名称"
+          prop="name"
+          :show-overflow-tooltip="true"
+        />
+        <el-table-column
+          label="创建者"
+          prop="create_name"
+          :show-overflow-tooltip="true"
+          width="150"
+        />
+        <el-table-column
+          label="创建时间"
+          align="center"
+          prop="create_time"
+          width="180"
+        />
+        <el-table-column
+          label="更新时间"
+          align="center"
+          prop="update_time"
+          width="180"
+        />
+        <el-table-column
+          label="操作"
+          align="center"
+          class-name="small-padding fixed-width"
+        >
           <template slot-scope="scope">
             <el-button
               v-permisaction="['process:admin:manager:clone']"
@@ -64,45 +104,57 @@
               type="text"
               icon="el-icon-receiving"
               @click="handleClone(scope.row)"
-            >克隆</el-button>
+              >克隆</el-button
+            >
             <el-button
               v-permisaction="['process:admin:manager:edit']"
               size="mini"
               type="text"
               icon="el-icon-edit"
               @click="handleEdit(scope.row)"
-            >编辑</el-button>
+              >编辑</el-button
+            >
             <el-button
               v-permisaction="['process:admin:manager:delete']"
               size="mini"
               type="text"
               icon="el-icon-delete"
               @click="handleDelete(scope.row)"
-            >删除</el-button>
+              >删除</el-button
+            >
           </template>
         </el-table-column>
       </el-table>
 
       <pagination
-        v-show="total>0"
+        v-show="total > 0"
         :total="total"
         :page.sync="queryParams.pageIndex"
         :limit.sync="queryParams.pageSize"
         @pagination="getList"
       />
       <el-drawer
-        :title="dialogProcessVisibleName===1?'新建流程':'编辑流程'"
+        :title="dialogProcessVisibleName === 1 ? '新建流程' : '编辑流程'"
         direction="rtl"
         :visible.sync="open"
         :before-close="handleClose"
         size="90%"
       >
         <div v-if="open" class="tpl-create-content" style="margin-right: 15px;">
-          <el-form ref="ruleForm" :model="ruleForm" :rules="rules" label-width="100px">
+          <el-form
+            ref="ruleForm"
+            :model="ruleForm"
+            :rules="rules"
+            label-width="100px"
+          >
             <el-row>
               <el-col :span="8">
                 <el-form-item label="名称" prop="name">
-                  <el-input v-model="ruleForm.name" placeholder="请输入流程名称" style="width: 100%" />
+                  <el-input
+                    v-model="ruleForm.name"
+                    placeholder="请输入流程名称"
+                    style="width: 100%"
+                  />
                 </el-form-item>
               </el-col>
               <el-col :span="8">
@@ -112,7 +164,12 @@
               </el-col>
               <el-col :span="8">
                 <el-form-item label="分类" prop="classify">
-                  <el-select v-model="ruleForm.classify" filterable placeholder="请选择流程分类" style="width: 100%">
+                  <el-select
+                    v-model="ruleForm.classify"
+                    filterable
+                    placeholder="请选择流程分类"
+                    style="width: 100%"
+                  >
                     <el-option
                       v-for="item in classifyListData"
                       :key="item.id"
@@ -126,7 +183,13 @@
             <el-row>
               <el-col :span="8">
                 <el-form-item label="模版" prop="tpls">
-                  <el-select v-model="ruleForm.tpls" filterable multiple placeholder="请选择模版" style="width: 100%">
+                  <el-select
+                    v-model="ruleForm.tpls"
+                    filterable
+                    multiple
+                    placeholder="请选择模版"
+                    style="width: 100%"
+                  >
                     <el-option
                       v-for="item in templates"
                       :key="item.id"
@@ -138,7 +201,14 @@
               </el-col>
               <el-col :span="8">
                 <el-form-item label="通知">
-                  <el-select v-model="ruleForm.notice" multiple filterable clearable placeholder="请选择流程任务" style="width: 100%">
+                  <el-select
+                    v-model="ruleForm.notice"
+                    multiple
+                    filterable
+                    clearable
+                    placeholder="请选择流程任务"
+                    style="width: 100%"
+                  >
                     <el-option label="推送" :value="1" />
                     <el-option label="IM消息" :value="2" />
                   </el-select>
@@ -146,7 +216,12 @@
               </el-col>
               <el-col :span="8">
                 <el-form-item label="模板类型" prop="sub">
-                  <el-select v-model="ruleForm.sub" filterable placeholder="请选择模板类型" style="width: 100%">
+                  <el-select
+                    v-model="ruleForm.sub"
+                    filterable
+                    placeholder="请选择模板类型"
+                    style="width: 100%"
+                  >
                     <el-option label="父流程" :value="0" />
                     <el-option label="子流程" :value="1" />
                   </el-select>
@@ -158,7 +233,7 @@
                 v-model="ruleForm.remarks"
                 placeholder="请输入流程描述"
                 type="textarea"
-                :autosize="{ minRows: 2, maxRows: 4}"
+                :autosize="{ minRows: 2, maxRows: 4 }"
                 style="width: 100%"
               />
             </el-form-item>
@@ -184,8 +259,18 @@
               </div>
             </el-form-item>
           </el-form>
-          <div style="text-align: center; margin-top: 20px; margin-bottom: 20px;">
-            <el-button type="primary" @click="dialogProcessVisibleName===1?submitForm('ruleForm'):editForm('ruleForm')">提交</el-button>
+          <div
+            style="text-align: center; margin-top: 20px; margin-bottom: 20px;"
+          >
+            <el-button
+              type="primary"
+              @click="
+                dialogProcessVisibleName === 1
+                  ? submitForm('ruleForm')
+                  : editForm('ruleForm')
+              "
+              >提交</el-button
+            >
             <el-button @click="handleClose">取 消</el-button>
           </div>
         </div>
@@ -202,21 +287,22 @@ import {
   processDetails,
   deleteProcess,
   cloneProcess
-} from '@/api/process/admin/process'
-
-import { classifyList } from '@/api/process/admin/classify'
-import { templateList } from '@/api/process/admin/template'
-import { taskList } from '@/api/process/admin/task'
-import { listUser } from '@/api/system/sysuser'
-import { listRole } from '@/api/system/role'
-import { listPost } from '@/api/system/post'
+} from "@/api/process/admin/process";
+import SaveForm from "@/components/save-form";
+import { classifyList } from "@/api/process/admin/classify";
+import { templateList } from "@/api/process/admin/template";
+import { taskList } from "@/api/process/admin/task";
+import { listUser } from "@/api/system/sysuser";
+import { listRole } from "@/api/system/role";
+import { listPost } from "@/api/system/post";
 // import { getOrdinaryDeptList } from '@/api/system/dept'
-import { treeselect } from '@/api/system/dept'
-import load from '@/utils/loading'
+import { treeselect } from "@/api/system/dept";
+import load from "@/utils/loading";
 export default {
-  name: 'Process',
+  name: "Process",
   components: {
-    WfdDesign: () => import('@/components/wfd/components/Wfd')
+    WfdDesign: () => import("@/components/wfd/components/Wfd"),
+    SaveForm
   },
   data() {
     return {
@@ -251,35 +337,27 @@ export default {
         page: 1,
         per_page: 10
       },
-      lang: 'zh',
+      lang: "zh",
       ruleForm: {},
       rules: {
         icon: [
-          { required: true, message: '请输入流程图标', trigger: 'change' }
-        ],
-        name: [
-          { required: true, message: '请输入流程名称', trigger: 'blur' }
+          { required: true, message: "请输入流程图标", trigger: "change" }
         ],
+        name: [{ required: true, message: "请输入流程名称", trigger: "blur" }],
         classify: [
-          { required: true, message: '请选择流程分类', trigger: 'change' }
-        ],
-        tpls: [
-          { required: true, message: '请选择模版', trigger: 'change' }
-        ],
-        sub: [
-          { required: true, message: '请选择模版类型', trigger: 'change' }
-        ],
-        structure: [
-          { required: true, message: '请设计流程', trigger: 'blur' }
+          { required: true, message: "请选择流程分类", trigger: "change" }
         ],
+        tpls: [{ required: true, message: "请选择模版", trigger: "change" }],
+        sub: [{ required: true, message: "请选择模版类型", trigger: "change" }],
+        structure: [{ required: true, message: "请设计流程", trigger: "blur" }],
         remarks: [
-          { required: true, message: '请输入流程描述', trigger: 'blur' }
+          { required: true, message: "请输入流程描述", trigger: "blur" }
         ]
       }
-    }
+    };
   },
-  created() {
-    this.getList()
+  mounted() {
+    this.getList();
   },
   methods: {
     // 获取任务列表
@@ -288,137 +366,151 @@ export default {
         page: 1,
         per_page: 99999
       }).then(response => {
-        this.taskListData = response.data.data
-      })
+        this.taskListData = response.data.data;
+      });
     },
     async getProcessList() {
       await processList({
         page: 1,
         per_page: 99999
-      }).then(response => {
-        const tempList = response.data.data || []
-        const subList = []
-        tempList.forEach(item => {
-          if (item.sub == 1) {
-            subList.push(item)
-          }
-        })
-        this.processData = subList
-      }).catch(() => {
-        load.endLoading()
       })
+        .then(response => {
+          const tempList = response.data.data || [];
+          const subList = [];
+          tempList.forEach(item => {
+            if (item.sub == 1) {
+              subList.push(item);
+            }
+          });
+          this.processData = subList;
+        })
+        .catch(() => {
+          load.endLoading();
+        });
     },
     // 获取流程分类列表
     async getClassifyList() {
       await classifyList({
         page: 1,
         per_page: 99999
-      }).then(response => {
-        this.classifyListData = response.data.data
-      }).catch(() => {
-        load.endLoading()
       })
+        .then(response => {
+          this.classifyListData = response.data.data;
+        })
+        .catch(() => {
+          load.endLoading();
+        });
     },
     // 获取模版列表
     async getTemplates() {
       await templateList({
         page: 1,
         per_page: 99999
-      }).then(response => {
-        this.templates = response.data.data
-      }).catch(() => {
-        load.endLoading()
       })
+        .then(response => {
+          this.templates = response.data.data;
+        })
+        .catch(() => {
+          load.endLoading();
+        });
     },
     // 获取用户
     async getUsers() {
       await listUser({
         pageSize: 999999
-      }).then(response => {
-        this.users = response.data.list
-      }).catch(() => {
-        load.endLoading()
       })
+        .then(response => {
+          this.users = response.data.list;
+        })
+        .catch(() => {
+          load.endLoading();
+        });
     },
     async getRoles() {
       await listRole({
         pageSize: 999999
-      }).then(response => {
-        this.roles = response.data.list
-      }).catch(() => {
-        load.endLoading()
       })
+        .then(response => {
+          this.roles = response.data.list;
+        })
+        .catch(() => {
+          load.endLoading();
+        });
     },
     // 获取部门
     async getDepartments() {
-      await treeselect().then(response => {
-        this.departments = response.data
-      }).catch(() => {
-        load.endLoading()
-      })
+      await treeselect()
+        .then(response => {
+          this.departments = response.data;
+        })
+        .catch(() => {
+          load.endLoading();
+        });
     },
     // 获取岗位
     async getPostOptions() {
       await listPost({
         page: 1,
         pageSize: 99999
-      }).then(response => {
-        this.postOptions = response.data.list
-      }).catch(() => {
-        load.endLoading()
       })
+        .then(response => {
+          this.postOptions = response.data.list;
+        })
+        .catch(() => {
+          load.endLoading();
+        });
     },
     /** 查询流程列表 */
     getList() {
-      this.loading = true
-      this.listQuery.page = this.queryParams.pageIndex
-      this.listQuery.per_page = this.queryParams.pageSize
+      this.loading = true;
+      this.listQuery.page = this.queryParams.pageIndex;
+      this.listQuery.per_page = this.queryParams.pageSize;
       processList(this.listQuery).then(response => {
-        this.processValueList = response.data.data
-        this.queryParams.pageIndex = response.data.page
-        this.queryParams.pageSize = response.data.per_page
-        this.total = response.data.total_count
-        this.loading = false
-      })
+        this.processValueList = response.data.data;
+        this.queryParams.pageIndex = response.data.page;
+        this.queryParams.pageSize = response.data.per_page;
+        this.total = response.data.total_count;
+        this.loading = false;
+      });
     },
     async getProcessInitData() {
-      await this.getClassifyList()
-      await this.getTemplates()
-      await this.getUsers()
-      await this.getRoles()
-      await this.getDepartments()
-      await this.getProcessList()
-      await this.getPostOptions()
+      await this.getClassifyList();
+      await this.getTemplates();
+      await this.getUsers();
+      await this.getRoles();
+      await this.getDepartments();
+      await this.getProcessList();
+      await this.getPostOptions();
     },
     async handleCreate() {
-      load.startLoading()
-      await this.getProcessInitData()
-      load.endLoading()
+      load.startLoading();
+      await this.getProcessInitData();
+      load.endLoading();
       this.ruleForm = {
         id: undefined,
-        name: '',
+        name: "",
         tpls: [],
-        structure: { 'edges': [], 'nodes': [], 'groups': [] },
-        classify: '',
+        structure: { edges: [], nodes: [], groups: [] },
+        classify: "",
         task: [],
         notice: [1],
         sub: 0,
-        icon: '',
-        remarks: ''
-      }
-      this.dialogProcessVisibleName = 1
-      this.open = true
-      this.wfdDesignRefresh = false
+        icon: "",
+        remarks: ""
+      };
+      this.dialogProcessVisibleName = 1;
+      this.open = true;
+      this.wfdDesignRefresh = false;
       this.$nextTick(() => {
-        this.wfdDesignRefresh = true
-      })
+        this.wfdDesignRefresh = true;
+      });
     },
     async handleEdit(row) {
-      this.dialogProcessVisibleName = 2
-      load.startLoading()
-      await this.getProcessInitData()
-      load.endLoading()
-      this.wfdDesignRefresh = false
+      this.dialogProcessVisibleName = 2;
+      load.startLoading();
+      await this.getProcessInitData();
+      load.endLoading();
+      this.wfdDesignRefresh = false;
       await processDetails({
         processId: row.id
       }).then(response => {
@@ -433,113 +525,132 @@ export default {
           sub: response.data.sub,
           icon: response.data.icon,
           remarks: response.data.remarks
-        }
-        this.wfdDesignRefresh = false
+        };
+        this.wfdDesignRefresh = false;
         this.$nextTick(() => {
-          this.wfdDesignRefresh = true
-        })
-      })
-      this.open = true
+          this.wfdDesignRefresh = true;
+        });
+      });
+      this.open = true;
     },
     handleClose(done) {
-      this.$confirm('确认关闭?')
+      this.$confirm("确认关闭?")
         .then(_ => {
-          this.open = false
+          this.open = false;
           if (done) {
-            done()
+            done();
           }
         })
-        .catch(_ => {})
+        .catch(_ => {});
     },
     verifyProcess(structureValue) {
       // console.log(structureValue)
       for (var r of structureValue.nodes) {
-        if (r.sort === undefined || r.sort === null || r.sort === '') {
-          return '流程节点顺序不能为空'
+        if (r.sort === undefined || r.sort === null || r.sort === "") {
+          return "流程节点顺序不能为空";
         }
         //  else if (r.label === undefined || r.label === null || r.label === '') {
         //   return '流程节点标题不能为空'
         // }
-        if (r.clazz === 'userTask' || r.clazz === 'receiveTask') {
-          if (r.assignType === undefined || r.assignType === null || r.assignType === '') {
-            return '审批节点或处理节点的处理人类型不能为空'
-          } else if (r.assignValue === undefined || r.assignValue === null || r.assignValue === '' || r.assignValue.length === 0) {
-            return '审批节点或处理节点的处理人不能为空'
+        if (r.clazz === "userTask" || r.clazz === "receiveTask") {
+          if (
+            r.assignType === undefined ||
+            r.assignType === null ||
+            r.assignType === ""
+          ) {
+            return "审批节点或处理节点的处理人类型不能为空";
+          } else if (
+            r.assignValue === undefined ||
+            r.assignValue === null ||
+            r.assignValue === "" ||
+            r.assignValue.length === 0
+          ) {
+            return "审批节点或处理节点的处理人不能为空";
           }
         }
       }
       //  else if (e.label === undefined || e.label === null || e.label === '') {
       //     return '流转标题不能为空'
       //   }
-      console.log(structureValue)
+      console.log(structureValue);
       for (var e of structureValue.edges) {
-        if (e.sort === undefined || e.sort === null || e.sort === '') {
-          return '流转顺序不能为空'
-        } else if (e.flowProperties === undefined || e.flowProperties === null || e.flowProperties === '') {
-          return '流转属性不能为空'
+        if (e.sort === undefined || e.sort === null || e.sort === "") {
+          return "流转顺序不能为空";
+        } else if (
+          e.flowProperties === undefined ||
+          e.flowProperties === null ||
+          e.flowProperties === ""
+        ) {
+          return "流转属性不能为空";
         }
       }
-      return ''
+      return "";
     },
     submitForm(formName) {
-      this.$refs[formName].validate((valid) => {
+      this.$refs[formName].validate(valid => {
         if (valid) {
-          var structureValue = this.$refs.wfd.graph.save()
+          var structureValue = this.$refs.wfd.graph.save();
           for (var n of structureValue.nodes) {
-            n.sort = '1'
-            n.activeOrder = false
-            const tempType = n.assignValue || []
+            n.sort = "1";
+            n.activeOrder = false;
+            const tempType = n.assignValue || [];
             if (tempType.includes(4)) {
-              n.isCounterSign = true
+              n.isCounterSign = true;
             } else {
-              n.isCounterSign = false
+              n.isCounterSign = false;
             }
           }
           for (var j of structureValue.edges) {
-            j.sort = '1'
-            j.flowProperties = '1'
+            j.sort = "1";
+            j.flowProperties = "1";
           }
-          var r = this.verifyProcess(structureValue)
-          if (r !== '') {
-            this.$message.error(r)
-            return
+          var r = this.verifyProcess(structureValue);
+          if (r !== "") {
+            this.$message.error(r);
+            return;
           }
-          if (structureValue.nodes.length > 0 && structureValue.edges.length > 0) {
-            this.ruleForm.structure = structureValue
+          if (
+            structureValue.nodes.length > 0 &&
+            structureValue.edges.length > 0
+          ) {
+            this.ruleForm.structure = structureValue;
             createProcess(this.ruleForm).then(response => {
-              this.getList()
-              this.open = false
-            })
+              this.getList();
+              this.open = false;
+            });
           } else {
-            this.$message.error('没有流程数据,请完善流程')
+            this.$message.error("没有流程数据,请完善流程");
           }
         }
-      })
+      });
     },
     editForm(formName) {
-      this.$refs[formName].validate((valid) => {
+      this.$refs[formName].validate(valid => {
         if (valid) {
-          var structureValue = this.$refs.wfd.graph.save()
+          var structureValue = this.$refs.wfd.graph.save();
           for (var n of structureValue.nodes) {
-            n.sort = '1'
-            n.activeOrder = false
-            const tempType = n.assignValue || []
+            n.sort = "1";
+            n.activeOrder = false;
+            const tempType = n.assignValue || [];
             if (tempType.includes(4)) {
-              n.isCounterSign = true
+              n.isCounterSign = true;
             } else {
-              n.isCounterSign = false
+              n.isCounterSign = false;
             }
           }
           for (var j of structureValue.edges) {
-            j.sort = '1'
-            j.flowProperties = '1'
+            j.sort = "1";
+            j.flowProperties = "1";
           }
-          var r = this.verifyProcess(structureValue)
-          if (r !== '') {
-            this.$message.error(r)
-            return
+          var r = this.verifyProcess(structureValue);
+          if (r !== "") {
+            this.$message.error(r);
+            return;
           }
-          if (structureValue.nodes.length > 0 && structureValue.edges.length > 0) {
+          if (
+            structureValue.nodes.length > 0 &&
+            structureValue.edges.length > 0
+          ) {
             updateProcess({
               id: this.ruleForm.id,
               name: this.ruleForm.name,
@@ -552,78 +663,82 @@ export default {
               icon: this.ruleForm.icon,
               remarks: this.ruleForm.remarks
             }).then(response => {
-              this.getList()
-              this.open = false
-            })
+              this.getList();
+              this.open = false;
+            });
           } else {
             this.$notify({
-              title: '错误',
-              message: '没有流程数据,请完善流程',
-              type: 'error'
-            })
+              title: "错误",
+              message: "没有流程数据,请完善流程",
+              type: "error"
+            });
           }
         }
-      })
+      });
     },
     handleQuery() {
-      this.queryParams.pageIndex = 1
-      this.queryParams.pageSize = 10
-      this.getList()
+      this.queryParams.pageIndex = 1;
+      this.queryParams.pageSize = 10;
+      this.getList();
     },
     handleDelete(row) {
-      this.$confirm('此操作将永久删除该数据, 是否继续?', '提示', {
-        confirmButtonText: '确定',
-        cancelButtonText: '取消',
-        type: 'warning'
-      }).then(() => {
-        deleteProcess({
-          processId: row.id
-        }).then(response => {
-          if (response !== undefined) {
-            this.getList()
-            this.$message({
-              type: 'success',
-              message: '流程已删除!'
-            })
-          }
-        })
-      }).catch(() => {
-        this.$message({
-          type: 'info',
-          message: '已取消删除'
-        })
+      this.$confirm("此操作将永久删除该数据, 是否继续?", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
       })
+        .then(() => {
+          deleteProcess({
+            processId: row.id
+          }).then(response => {
+            if (response !== undefined) {
+              this.getList();
+              this.$message({
+                type: "success",
+                message: "流程已删除!"
+              });
+            }
+          });
+        })
+        .catch(() => {
+          this.$message({
+            type: "info",
+            message: "已取消删除"
+          });
+        });
     },
     handleSelectionChange() {},
     handleSave(values) {
       if (values.list.length > 0) {
-        this.ruleForm.form_structure = values
+        this.ruleForm.form_structure = values;
       } else {
-        this.ruleForm.form_structure = ''
+        this.ruleForm.form_structure = "";
       }
     },
     handleClone(row) {
-      this.$confirm(`确认克隆流程 < ${row.name} > ?`, '提示', {
-        confirmButtonText: '确定',
-        cancelButtonText: '取消',
-        type: 'info'
-      }).then(() => {
-        cloneProcess(row.id).then(() => {
-          this.getList()
-          this.$message({
-            type: 'success',
-            message: '流程已克隆!'
-          })
-        })
-      }).catch(() => {
-        this.$message({
-          type: 'info',
-          message: '已取消'
-        })
+      this.$confirm(`确认克隆流程 < ${row.name} > ?`, "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "info"
       })
+        .then(() => {
+          cloneProcess(row.id).then(() => {
+            this.getList();
+            this.$message({
+              type: "success",
+              message: "流程已克隆!"
+            });
+          });
+        })
+        .catch(() => {
+          this.$message({
+            type: "info",
+            message: "已取消"
+          });
+        });
     }
   }
-}
+};
 </script>
 
 <style scoped>

+ 192 - 126
src/views/process/admin/template-manager.vue

@@ -1,7 +1,12 @@
 <template>
   <div class="app-container">
     <el-card class="box-card">
-      <el-form ref="listQuery" :model="listQuery" :inline="true">
+      <save-form
+        ref="listQuery"
+        :model="listQuery"
+        :inline="true"
+        @submit="handleQuery"
+      >
         <el-form-item label="模版名称">
           <el-input
             v-model="listQuery.name"
@@ -13,9 +18,15 @@
           />
         </el-form-item>
         <el-form-item>
-          <el-button type="primary" icon="el-icon-search" size="small" @click="handleQuery">搜索</el-button>
+          <el-button
+            type="primary"
+            icon="el-icon-search"
+            size="small"
+            native-type="submit"
+            >搜索</el-button
+          >
         </el-form-item>
-      </el-form>
+      </save-form>
 
       <el-row :gutter="10" class="mb8">
         <el-col :span="1.5">
@@ -25,7 +36,8 @@
             icon="el-icon-plus"
             size="mini"
             @click="handleCreate"
-          >新增</el-button>
+            >新增</el-button
+          >
         </el-col>
         <!-- <el-col :span="1.5">
           <el-button
@@ -49,14 +61,42 @@
         </el-col> -->
       </el-row>
 
-      <el-table v-loading="loading" border :data="tplList" @selection-change="handleSelectionChange">
+      <el-table
+        v-loading="loading"
+        border
+        :data="tplList"
+        @selection-change="handleSelectionChange"
+      >
         <el-table-column type="selection" width="55" align="center" />
         <el-table-column label="ID" prop="id" width="120" />
-        <el-table-column label="名称" prop="name" :show-overflow-tooltip="true" />
-        <el-table-column label="创建者" prop="create_name" :show-overflow-tooltip="true" width="150" />
-        <el-table-column label="创建时间" align="center" prop="create_time" width="180" />
-        <el-table-column label="更新时间" align="center" prop="update_time" width="180" />
-        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <el-table-column
+          label="名称"
+          prop="name"
+          :show-overflow-tooltip="true"
+        />
+        <el-table-column
+          label="创建者"
+          prop="create_name"
+          :show-overflow-tooltip="true"
+          width="150"
+        />
+        <el-table-column
+          label="创建时间"
+          align="center"
+          prop="create_time"
+          width="180"
+        />
+        <el-table-column
+          label="更新时间"
+          align="center"
+          prop="update_time"
+          width="180"
+        />
+        <el-table-column
+          label="操作"
+          align="center"
+          class-name="small-padding fixed-width"
+        >
           <template slot-scope="scope">
             <el-button
               v-permisaction="['process:admin:template:clone']"
@@ -64,41 +104,49 @@
               type="text"
               icon="el-icon-receiving"
               @click="handleClone(scope.row)"
-            >克隆</el-button>
+              >克隆</el-button
+            >
             <el-button
               v-permisaction="['process:admin:template:edit']"
               size="mini"
               type="text"
               icon="el-icon-edit"
               @click="handleEdit(scope.row)"
-            >编辑</el-button>
+              >编辑</el-button
+            >
             <el-button
               v-permisaction="['process:admin:template:delete']"
               size="mini"
               type="text"
               icon="el-icon-delete"
               @click="handleDelete(scope.row)"
-            >删除</el-button>
+              >删除</el-button
+            >
           </template>
         </el-table-column>
       </el-table>
 
       <pagination
-        v-show="total>0"
+        v-show="total > 0"
         :total="total"
         :page.sync="queryParams.pageIndex"
         :limit.sync="queryParams.pageSize"
         @pagination="getList"
       />
       <el-drawer
-        :title="dialogFormVisibleName===1?'新建模版':'编辑模版'"
+        :title="dialogFormVisibleName === 1 ? '新建模版' : '编辑模版'"
         direction="rtl"
         :visible.sync="open"
         :before-close="handleClose"
         size="90%"
       >
         <div class="tpl-create-content">
-          <el-form ref="ruleForm" :model="ruleForm" :rules="rules" label-width="100px">
+          <el-form
+            ref="ruleForm"
+            :model="ruleForm"
+            :rules="rules"
+            label-width="100px"
+          >
             <el-form-item label="名称" prop="name">
               <el-input v-model="ruleForm.name" />
             </el-form-item>
@@ -106,7 +154,9 @@
               <el-input v-model="ruleForm.remarks" type="textarea" />
             </el-form-item>
             <el-form-item label="模版" prop="form_structure">
-              <div style="border-radius: 4px; border: 1px solid #ccc; overflow:hidden">
+              <div
+                style="border-radius: 4px; border: 1px solid #ccc; overflow:hidden"
+              >
                 <fm-making-form
                   ref="makingform"
                   style="height: 600px;"
@@ -115,7 +165,13 @@
                   upload
                   generate-code
                   generate-json
-                  :advance-fields="['editor', 'imgupload', 'file', 'subform', 'cascader']"
+                  :advance-fields="[
+                    'editor',
+                    'imgupload',
+                    'file',
+                    'subform',
+                    'cascader'
+                  ]"
                 >
                   <template slot="action" />
                 </fm-making-form>
@@ -123,7 +179,15 @@
             </el-form-item>
           </el-form>
           <div style="text-align: center">
-            <el-button type="primary" @click="dialogFormVisibleName===1?submitForm('ruleForm'):editForm('ruleForm')">提交</el-button>
+            <el-button
+              type="primary"
+              @click="
+                dialogFormVisibleName === 1
+                  ? submitForm('ruleForm')
+                  : editForm('ruleForm')
+              "
+              >提交</el-button
+            >
             <el-button @click="handleClose">取 消</el-button>
           </div>
         </div>
@@ -133,7 +197,7 @@
 </template>
 
 <script>
-import Vue from 'vue'
+import Vue from "vue";
 
 import {
   templateList,
@@ -142,23 +206,23 @@ import {
   editTemplate,
   deleteTemplate,
   cloneTemplate
-} from '@/api/process/admin/template'
-
+} from "@/api/process/admin/template";
+import SaveForm from "@/components/save-form";
 // 表单设计
-import {
-  GenerateForm,
-  MakingForm
-} from '@/components/VueFormMaking'
-import '@/components/VueFormMaking/styles/FormMaking.css'
+import { GenerateForm, MakingForm } from "@/components/VueFormMaking";
+import "@/components/VueFormMaking/styles/FormMaking.css";
 
-import ace from 'ace-builds'
-import 'ace-builds/webpack-resolver'
-Vue.use(ace)
-Vue.use(GenerateForm)
-Vue.use(MakingForm)
+import ace from "ace-builds";
+import "ace-builds/webpack-resolver";
+Vue.use(ace);
+Vue.use(GenerateForm);
+Vue.use(MakingForm);
 
 export default {
-  name: 'Template',
+  name: "Template",
+  components: {
+    SaveForm
+  },
   data() {
     return {
       dialogFormVisibleName: 1,
@@ -183,52 +247,50 @@ export default {
       },
       ruleForm: {
         id: undefined,
-        name: '',
-        remarks: '',
-        form_structure: ''
+        name: "",
+        remarks: "",
+        form_structure: ""
       },
       rules: {
-        name: [
-          { required: true, message: '请输入模版名称', trigger: 'blur' }
-        ],
+        name: [{ required: true, message: "请输入模版名称", trigger: "blur" }],
         form_structure: [
-          { required: true, message: '请设计模版', trigger: 'blur' }
+          { required: true, message: "请设计模版", trigger: "blur" }
         ]
       }
-    }
+    };
   },
-  created() {
-    this.getList()
+  mounted() {
+    this.getList();
   },
   methods: {
     /** 查询模版列表 */
     getList() {
-      this.loading = true
-      this.listQuery.page = this.queryParams.pageIndex
-      this.listQuery.per_page = this.queryParams.pageSize
+      this.loading = true;
+      this.listQuery.page = this.queryParams.pageIndex;
+      this.listQuery.per_page = this.queryParams.pageSize;
       templateList(this.listQuery).then(response => {
-        this.tplList = response.data.data
-        this.queryParams.pageIndex = response.data.page
-        this.queryParams.pageSize = response.data.per_page
-        this.total = response.data.total_count
-        this.loading = false
-      })
+        this.tplList = response.data.data;
+        this.queryParams.pageIndex = response.data.page;
+        this.queryParams.pageSize = response.data.per_page;
+        this.total = response.data.total_count;
+        this.loading = false;
+      });
     },
     handleCreate() {
       this.ruleForm = {
         id: undefined,
-        name: '',
-        remarks: '',
-        form_structure: ''
-      }
-      this.dialogFormVisibleName = 1
-      this.open = true
+        name: "",
+        remarks: "",
+        form_structure: ""
+      };
+      this.dialogFormVisibleName = 1;
+      this.open = true;
       this.$nextTick(() => {
-        this.$refs.makingform.handleClear()
-      })
+        this.$refs.makingform.handleClear();
+      });
     },
     handleEdit(row) {
-      this.dialogFormVisibleName = 2
+      this.dialogFormVisibleName = 2;
       templateDetails({
         template_id: row.id
       }).then(response => {
@@ -237,102 +299,106 @@ export default {
           name: response.data.name,
           remarks: response.data.remarks,
           form_structure: response.data.remarks
-        }
-        this.open = true
+        };
+        this.open = true;
         this.$nextTick(() => {
-          this.$refs.makingform.setJSON(response.data.form_structure)
-        })
-      })
+          this.$refs.makingform.setJSON(response.data.form_structure);
+        });
+      });
     },
     handleClose(done) {
-      this.$confirm('确认关闭?')
+      this.$confirm("确认关闭?")
         .then(_ => {
-          this.open = false
+          this.open = false;
           if (done) {
-            done()
+            done();
           }
         })
-        .catch(_ => {})
+        .catch(_ => {});
     },
     submitForm(formName) {
-      this.handleSave(this.$refs.makingform.getJSON())
-      this.$refs[formName].validate((valid) => {
+      this.handleSave(this.$refs.makingform.getJSON());
+      this.$refs[formName].validate(valid => {
         if (valid) {
           createTemplate(this.ruleForm).then(() => {
-            this.getList()
-            this.open = false
-          })
+            this.getList();
+            this.open = false;
+          });
         }
-      })
+      });
     },
     editForm(formName) {
-      this.handleSave(this.$refs.makingform.getJSON())
-      this.$refs[formName].validate((valid) => {
+      this.handleSave(this.$refs.makingform.getJSON());
+      this.$refs[formName].validate(valid => {
         if (valid) {
           editTemplate(this.ruleForm).then(() => {
-            this.getList()
-            this.open = false
-          })
+            this.getList();
+            this.open = false;
+          });
         }
-      })
+      });
     },
     handleQuery() {
-      this.queryParams.pageIndex = 1
-      this.queryParams.pageSize = 10
-      this.getList()
+      this.queryParams.pageIndex = 1;
+      this.queryParams.pageSize = 10;
+      this.getList();
     },
     handleDelete(row) {
-      this.$confirm('此操作将永久删除该数据, 是否继续?', '提示', {
-        confirmButtonText: '确定',
-        cancelButtonText: '取消',
-        type: 'warning'
-      }).then(() => {
-        deleteTemplate({
-          templateId: row.id
-        }).then(response => {
-          if (response !== undefined) {
-            this.getList()
-            this.$message({
-              type: 'success',
-              message: '模版已删除!'
-            })
-          }
-        })
-      }).catch(() => {
-        this.$message({
-          type: 'info',
-          message: '已取消删除'
-        })
+      this.$confirm("此操作将永久删除该数据, 是否继续?", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
       })
+        .then(() => {
+          deleteTemplate({
+            templateId: row.id
+          }).then(response => {
+            if (response !== undefined) {
+              this.getList();
+              this.$message({
+                type: "success",
+                message: "模版已删除!"
+              });
+            }
+          });
+        })
+        .catch(() => {
+          this.$message({
+            type: "info",
+            message: "已取消删除"
+          });
+        });
     },
     handleSelectionChange() {},
     handleSave(values) {
       if (values.list.length > 0) {
-        this.ruleForm.form_structure = values
+        this.ruleForm.form_structure = values;
       } else {
-        this.ruleForm.form_structure = ''
+        this.ruleForm.form_structure = "";
       }
     },
     handleClone(row) {
-      this.$confirm(`确认克隆模版 < ${row.name} > ?`, '提示', {
-        confirmButtonText: '确定',
-        cancelButtonText: '取消',
-        type: 'info'
-      }).then(() => {
-        cloneTemplate(row.id).then(() => {
-          this.getList()
-          this.$message({
-            type: 'success',
-            message: '模版已克隆!'
-          })
-        })
-      }).catch(() => {
-        this.$message({
-          type: 'info',
-          message: '已取消'
-        })
+      this.$confirm(`确认克隆模版 < ${row.name} > ?`, "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "info"
       })
+        .then(() => {
+          cloneTemplate(row.id).then(() => {
+            this.getList();
+            this.$message({
+              type: "success",
+              message: "模版已克隆!"
+            });
+          });
+        })
+        .catch(() => {
+          this.$message({
+            type: "info",
+            message: "已取消"
+          });
+        });
     }
   }
-}
+};
 </script>

+ 12 - 6
src/views/process/list/all.vue

@@ -1,9 +1,13 @@
 <template>
   <div class="app-container">
     <el-card class="box-card">
-      <el-form ref="listQuery" :model="listQuery" :inline="true">
-        <WorkOrderSearch :genre="'all'" @handleSearch="handleSearch" />
-      </el-form>
+      <save-form ref="listQuery" :model="listQuery" :inline="true">
+        <WorkOrderSearch
+          :genre="'all'"
+          :list="listQuery"
+          @handleSearch="handleSearch"
+        />
+      </save-form>
 
       <el-table
         v-loading="loading"
@@ -184,9 +188,9 @@ import TransferInversion from "./model/transferInversion";
 import load from "@/utils/loading";
 // 搜索
 import WorkOrderSearch from "./components/search/index";
-
+import SaveForm from "@/components/save-form";
 export default {
-  components: { WorkOrderSearch, TransferInversion },
+  components: { WorkOrderSearch, TransferInversion, SaveForm },
   data() {
     return {
       users: [],
@@ -208,7 +212,7 @@ export default {
       }
     };
   },
-  created() {
+  mounted() {
     this.getList();
   },
   methods: {
@@ -229,6 +233,8 @@ export default {
       for (var k in val) {
         this.listQuery[k] = val[k];
       }
+      this.$refs.listQuery.save(this.listQuery);
+      this.$refs.listQuery.save(this.queryParams, "page");
       this.getList();
     },
     handleView(row) {

+ 98 - 70
src/views/process/list/apply-process-list.vue

@@ -1,8 +1,13 @@
 <template>
   <div class="app-container">
     <el-card class="box-card remove-padding-bottom">
-      <el-form ref="listQuery" :model="listQuery" :inline="true">
-        <el-form-item label="流程名称">
+      <save-form
+        ref="listQuery"
+        :model="listQuery"
+        :inline="true"
+        @submit="handleQuery"
+      >
+        <el-form-item label="流程名称" prop="name">
           <el-input
             v-model="listQuery.name"
             placeholder="请输入流程名称"
@@ -13,12 +18,18 @@
           />
         </el-form-item>
         <el-form-item>
-          <el-button type="primary" icon="el-icon-search" size="small" @click="handleQuery">搜索</el-button>
+          <el-button
+            type="primary"
+            icon="el-icon-search"
+            native-type="submit"
+            size="small"
+            >搜索</el-button
+          >
         </el-form-item>
-      </el-form>
+      </save-form>
 
       <div v-for="item in processLists" :key="item.id">
-        <div v-if="item.process_list.length!==0">
+        <div v-if="item.process_list.length !== 0">
           <div class="workflow-classify-title">
             {{ item.name }}
           </div>
@@ -27,11 +38,19 @@
               <el-tooltip :key="buttonItem.id" effect="dark" placement="top">
                 <div slot="content">
                   <div style="font-size: 16px;">{{ buttonItem.name }}</div>
-                  <div style="width: 250px; padding-top: 10px;line-height: 1.2;">{{ buttonItem.remarks }}</div>
+                  <div
+                    style="width: 250px; padding-top: 10px;line-height: 1.2;"
+                  >
+                    {{ buttonItem.remarks }}
+                  </div>
                 </div>
                 <div
                   class="workflow-classify-div"
-                  :style="(buttonIndex + 1) % 5 === 0 ? {'padding-right': 0} : {'padding-right': '12px'}"
+                  :style="
+                    (buttonIndex + 1) % 5 === 0
+                      ? { 'padding-right': 0 }
+                      : { 'padding-right': '12px' }
+                  "
                 >
                   <el-button
                     style="width: 100%"
@@ -40,7 +59,10 @@
                   >
                     <div class="process-button-div">
                       <div class="process-div-icon">
-                        <e-icon class="process-div-el-icon" :icon-name="buttonItem.icon" />
+                        <e-icon
+                          class="process-div-el-icon"
+                          :icon-name="buttonItem.icon"
+                        />
                       </div>
                       <div class="process-div-body">
                         <div class="process-div-title ellipsis">
@@ -63,94 +85,100 @@
 </template>
 
 <script>
-import { classifyProcessList } from '@/api/process/admin/process'
-
+import { classifyProcessList } from "@/api/process/admin/process";
+import SaveForm from "@/components/save-form";
 export default {
-  name: 'ApplyProcessList',
+  name: "ApplyProcessList",
+  components: {
+    SaveForm
+  },
   data() {
     return {
       processLists: [],
       listQuery: {}
-    }
+    };
   },
-  created() {
-    this.getProcessList()
+  mounted() {
+    this.getProcessList();
   },
   methods: {
     getProcessList() {
       classifyProcessList(this.listQuery).then(response => {
-        this.processLists = response.data
-      })
+        this.processLists = response.data;
+      });
     },
     handleQuery() {
-      this.getProcessList()
+      this.getProcessList();
     },
     submitWorkOrder(processId) {
-      this.$router.push({ path: '/process/create-ticket', query: { processId: processId }})
+      this.$router.push({
+        path: "/process/create-ticket",
+        query: { processId: processId }
+      });
     }
   }
-}
+};
 </script>
 
 <style scoped>
-  .workflow-classify-title {
-    border-left: 3px solid rgb(64, 158, 255);
-    padding-left: 5px;
-  }
+.workflow-classify-title {
+  border-left: 3px solid rgb(64, 158, 255);
+  padding-left: 5px;
+}
 
-  .workflow-classify-div {
-    width: 20%;
-    display: inline-block;
-    margin-left: 0;
-    margin-top: 12px;
-  }
+.workflow-classify-div {
+  width: 20%;
+  display: inline-block;
+  margin-left: 0;
+  margin-top: 12px;
+}
 
-  .el-card__body {
-    padding-bottom: 0;
-  }
+.el-card__body {
+  padding-bottom: 0;
+}
 
-  .process-button-div {
-    width: 180px;
-    height: 50px;
-  }
+.process-button-div {
+  width: 180px;
+  height: 50px;
+}
 
-  .process-div-icon {
-    float: left;
-    width: 50px;
-    height: 100%;
-    margin-right: 10px;
-  }
+.process-div-icon {
+  float: left;
+  width: 50px;
+  height: 100%;
+  margin-right: 10px;
+}
 
-  .process-div-el-icon {
-    font-size: 32px;
-    line-height: 50px;
-    color: #606266;
-  }
+.process-div-el-icon {
+  font-size: 32px;
+  line-height: 50px;
+  color: #606266;
+}
 
-  .process-div-body {
-    float: left;
-    width: 120px;
-    height: 100%;
-    text-align: left;
-  }
+.process-div-body {
+  float: left;
+  width: 120px;
+  height: 100%;
+  text-align: left;
+}
 
-  .process-div-title {
-    font-size: 15px;
-    margin-top: 6px;
-    color: #606266;
-    height: 18px;
-    line-height: 18px;
-  }
+.process-div-title {
+  font-size: 15px;
+  margin-top: 6px;
+  color: #606266;
+  height: 18px;
+  line-height: 18px;
+}
 
-  .process-div-remarks {
-    color: #999999;
-    margin-top: 6px;
-    font-size: 12px;
-  }
+.process-div-remarks {
+  color: #999999;
+  margin-top: 6px;
+  font-size: 12px;
+}
 
-  .ellipsis {
-    overflow: hidden;
-    text-overflow: ellipsis;
-    white-space: nowrap;
-  }
+.ellipsis {
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
 </style>

+ 8 - 1
src/views/process/list/components/search/index.vue

@@ -107,7 +107,7 @@ import { parseTime } from "@/utils";
 export default {
   name: "WorkOrderSearch",
   // eslint-disable-next-line vue/require-prop-types
-  props: ["genre"],
+  props: ["genre", "list"],
   data() {
     return {
       loading: false,
@@ -147,6 +147,13 @@ export default {
       }
     };
   },
+  created() {
+    // console.log(this.list, "child component");
+    this.listQuery = { ...this.list };
+    if (this.listQuery.startTime && this.listQuery.endTime) {
+      this.timeValue = [this.listQuery.startTime, this.listQuery.endTime];
+    }
+  },
   methods: {
     getList() {
       if (

+ 12 - 7
src/views/process/list/my-create.vue

@@ -1,11 +1,13 @@
 <template>
   <div class="app-container">
     <el-card class="box-card">
-      <el-form ref="listQuery" :model="listQuery" :inline="true">
-        <el-form ref="listQuery" :model="listQuery" :inline="true">
-          <WorkOrderSearch :genre="'my-create'" @handleSearch="handleSearch" />
-        </el-form>
-      </el-form>
+      <save-form ref="listQuery" :model="listQuery" :inline="true">
+        <WorkOrderSearch
+          :genre="'my-create'"
+          :list="listQuery"
+          @handleSearch="handleSearch"
+        />
+      </save-form>
 
       <el-table
         v-loading="loading"
@@ -161,11 +163,12 @@ import {
   reopenWorkOrder,
   unityWorkOrder
 } from "@/api/process/work-order";
+import SaveForm from "@/components/save-form";
 
 // 搜索
 import WorkOrderSearch from "./components/search/index";
 export default {
-  components: { WorkOrderSearch },
+  components: { WorkOrderSearch, SaveForm },
   data() {
     return {
       users: [],
@@ -190,7 +193,7 @@ export default {
       }
     };
   },
-  created() {
+  mounted() {
     this.getList();
   },
   methods: {
@@ -211,6 +214,8 @@ export default {
       for (var k in val) {
         this.listQuery[k] = val[k];
       }
+      this.$refs.listQuery.save(this.listQuery);
+      this.$refs.listQuery.save(this.queryParams, "page");
       this.getList();
     },
     handleView(row) {

+ 12 - 8
src/views/process/list/related.vue

@@ -1,11 +1,13 @@
 <template>
   <div class="app-container">
     <el-card class="box-card">
-      <el-form ref="listQuery" :model="listQuery" :inline="true">
-        <el-form ref="listQuery" :model="listQuery" :inline="true">
-          <WorkOrderSearch :genre="'my-create'" @handleSearch="handleSearch" />
-        </el-form>
-      </el-form>
+      <save-form ref="listQuery" :model="listQuery" :inline="true">
+        <WorkOrderSearch
+          :genre="'my-create'"
+          :list="listQuery"
+          @handleSearch="handleSearch"
+        />
+      </save-form>
 
       <el-table
         v-loading="loading"
@@ -143,9 +145,9 @@ import { workOrderList } from "@/api/process/work-order";
 import TransferInversion from "./model/transferInversion";
 // 搜索
 import WorkOrderSearch from "./components/search/index";
-
+import SaveForm from "@/components/save-form";
 export default {
-  components: { WorkOrderSearch, TransferInversion },
+  components: { WorkOrderSearch, TransferInversion, SaveForm },
   data() {
     return {
       users: [],
@@ -177,7 +179,7 @@ export default {
       }
     };
   },
-  created() {
+  mounted() {
     this.getList();
   },
   methods: {
@@ -198,6 +200,8 @@ export default {
       for (var k in val) {
         this.listQuery[k] = val[k];
       }
+      this.$refs.listQuery.save(this.listQuery);
+      this.$refs.listQuery.save(this.queryParams, "page");
       this.getList();
     },
     handleView(row) {

+ 15 - 7
src/views/process/list/upcoming.vue

@@ -1,11 +1,13 @@
 <template>
   <div class="app-container">
     <el-card class="box-card">
-      <el-form ref="listQuery" :model="listQuery" :inline="true">
-        <el-form ref="listQuery" :model="listQuery" :inline="true">
-          <WorkOrderSearch :genre="'upcoming'" @handleSearch="handleSearch" />
-        </el-form>
-      </el-form>
+      <save-form ref="listQuery" :model="listQuery" :inline="true">
+        <WorkOrderSearch
+          :genre="'upcoming'"
+          :list="listQuery"
+          @handleSearch="handleSearch"
+        />
+      </save-form>
 
       <el-table
         v-loading="loading"
@@ -148,6 +150,7 @@
 </template>
 
 <script>
+import SaveForm from "@/components/save-form";
 import { workOrderList } from "@/api/process/work-order";
 import { listUser } from "@/api/system/sysuser";
 import { initNumberHtml } from "@/utils/costum";
@@ -157,7 +160,7 @@ import load from "@/utils/loading";
 import WorkOrderSearch from "./components/search/index";
 
 export default {
-  components: { WorkOrderSearch, TransferInversion },
+  components: { WorkOrderSearch, TransferInversion, SaveForm },
   data() {
     return {
       users: [],
@@ -179,11 +182,12 @@ export default {
       }
     };
   },
-  created() {
+  mounted() {
     this.getList();
   },
   methods: {
     getList() {
+      // console.log(this.listQuery, "121212");
       this.loading = true;
       this.listQuery.page = this.queryParams.pageIndex;
       this.listQuery.per_page = this.queryParams.pageSize;
@@ -199,9 +203,13 @@ export default {
       });
     },
     handleSearch(val) {
+      //
       for (var k in val) {
         this.listQuery[k] = val[k];
       }
+
+      this.$refs.listQuery.save(this.listQuery);
+      this.$refs.listQuery.save(this.queryParams, "page");
       this.getList();
     },
     handleView(row) {

+ 157 - 102
src/views/system/dept/index.vue

@@ -1,7 +1,12 @@
 <template>
   <div class="app-container">
     <el-card class="box-card">
-      <el-form :inline="true">
+      <save-form
+        ref="queryForm"
+        :model="queryParams"
+        :inline="true"
+        @submit="handleQuery"
+      >
         <el-form-item label="部门名称">
           <el-input
             v-model="queryParams.deptName"
@@ -17,8 +22,9 @@
             type="primary"
             icon="el-icon-search"
             size="small"
-            @click="handleQuery"
-          >搜索</el-button>
+            native-type="submit"
+            >搜索</el-button
+          >
           <el-button
             v-permisaction="['system:sysdept:add']"
             class="filter-item"
@@ -26,9 +32,10 @@
             icon="el-icon-plus"
             size="small"
             @click="handleAdd"
-          >新增</el-button>
+            >新增</el-button
+          >
         </el-form-item>
-      </el-form>
+      </save-form>
 
       <el-table
         v-loading="loading"
@@ -36,7 +43,7 @@
         row-key="deptId"
         border
         default-expand-all
-        :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
+        :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
       >
         <el-table-column prop="deptName" label="部门名称" />
         <el-table-column prop="sort" label="排序" width="200" />
@@ -45,15 +52,25 @@
             <el-tag
               :type="scope.row.status === '1' ? 'danger' : 'success'"
               disable-transitions
-            >{{ scope.row.status === '1' ? '停用' : '正常' }}</el-tag>
+              >{{ scope.row.status === "1" ? "停用" : "正常" }}</el-tag
+            >
           </template>
         </el-table-column>
-        <el-table-column label="创建时间" align="center" prop="create_time" width="200">
+        <el-table-column
+          label="创建时间"
+          align="center"
+          prop="create_time"
+          width="200"
+        >
           <template slot-scope="scope">
             <span>{{ parseTime(scope.row.create_time) }}</span>
           </template>
         </el-table-column>
-        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <el-table-column
+          label="操作"
+          align="center"
+          class-name="small-padding fixed-width"
+        >
           <template slot-scope="scope">
             <el-button
               v-permisaction="['system:sysdept:edit']"
@@ -61,14 +78,16 @@
               type="text"
               icon="el-icon-edit"
               @click="handleUpdate(scope.row)"
-            >编辑</el-button>
+              >编辑</el-button
+            >
             <el-button
               v-permisaction="['system:sysdept:add']"
               size="mini"
               type="text"
               icon="el-icon-plus"
               @click="handleAdd(scope.row)"
-            >新增</el-button>
+              >新增</el-button
+            >
             <el-button
               v-if="scope.row.p_id != 0"
               v-permisaction="['system:sysdept:remove']"
@@ -76,7 +95,8 @@
               type="text"
               icon="el-icon-delete"
               @click="handleDelete(scope.row)"
-            >删除</el-button>
+              >删除</el-button
+            >
           </template>
         </el-table-column>
       </el-table>
@@ -104,12 +124,21 @@
           </el-col>
           <el-col :span="12">
             <el-form-item label="显示排序" prop="orderNum">
-              <el-input-number v-model="form.sort" controls-position="right" :min="0" />
+              <el-input-number
+                v-model="form.sort"
+                controls-position="right"
+                :min="0"
+              />
             </el-form-item>
           </el-col>
           <el-col :span="12">
             <el-form-item label="负责人" prop="leader">
-              <el-select v-model="form.leader" clearable filterable placeholder="请选择负责人">
+              <el-select
+                v-model="form.leader"
+                clearable
+                filterable
+                placeholder="请选择负责人"
+              >
                 <el-option
                   v-for="item in users"
                   :key="item.userId"
@@ -122,7 +151,12 @@
           <el-col :span="12">
             <el-form-item label="所属分部" prop="organId">
               <!-- <el-input v-model="form.organId" placeholder="请输入所属分部" /> -->
-              <el-select v-model="form.organId" clearable filterable placeholder="请选择所属分部">
+              <el-select
+                v-model="form.organId"
+                clearable
+                filterable
+                placeholder="请选择所属分部"
+              >
                 <el-option
                   v-for="item in organList"
                   :key="item.id"
@@ -134,12 +168,20 @@
           </el-col>
           <el-col :span="12">
             <el-form-item label="联系电话" prop="phone">
-              <el-input v-model="form.phone" placeholder="请输入联系电话" maxlength="11" />
+              <el-input
+                v-model="form.phone"
+                placeholder="请输入联系电话"
+                maxlength="11"
+              />
             </el-form-item>
           </el-col>
           <el-col :span="12">
             <el-form-item label="邮箱" prop="email">
-              <el-input v-model="form.email" placeholder="请输入邮箱" maxlength="50" />
+              <el-input
+                v-model="form.email"
+                placeholder="请输入邮箱"
+                maxlength="50"
+              />
             </el-form-item>
           </el-col>
           <el-col :span="12">
@@ -149,7 +191,8 @@
                   v-for="dict in statusOptions"
                   :key="dict.value"
                   :label="dict.value"
-                >{{ dict.label }}</el-radio>
+                  >{{ dict.label }}</el-radio
+                >
               </el-radio-group>
             </el-form-item>
           </el-col>
@@ -164,14 +207,21 @@
 </template>
 
 <script>
-import { listUser } from '@/api/system/sysuser'
-import { getDeptList, getDept, delDept, addDept, updateDept, queryEmployeeOrgan } from '@/api/system/dept'
-import Treeselect from '@riophae/vue-treeselect'
-import '@riophae/vue-treeselect/dist/vue-treeselect.css'
-
+import { listUser } from "@/api/system/sysuser";
+import {
+  getDeptList,
+  getDept,
+  delDept,
+  addDept,
+  updateDept,
+  queryEmployeeOrgan
+} from "@/api/system/dept";
+import Treeselect from "@riophae/vue-treeselect";
+import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+import SaveForm from "@/components/save-form";
 export default {
-  name: 'Dept',
-  components: { Treeselect },
+  name: "Dept",
+  components: { Treeselect, SaveForm },
   data() {
     return {
       // 遮罩层
@@ -183,7 +233,7 @@ export default {
       // 分部列表
       organList: [],
       // 弹出层标题
-      title: '',
+      title: "",
       isEdit: false,
       // 是否显示弹出层
       open: false,
@@ -198,95 +248,100 @@ export default {
       // 表单校验
       rules: {
         parentId: [
-          { required: true, message: '上级部门不能为空', trigger: 'blur' }
+          { required: true, message: "上级部门不能为空", trigger: "blur" }
         ],
         deptName: [
-          { required: true, message: '部门名称不能为空', trigger: 'blur' }
+          { required: true, message: "部门名称不能为空", trigger: "blur" }
         ],
         leader: [
-          { required: true, message: '部门负责人不能为空', trigger: 'blur' }
+          { required: true, message: "部门负责人不能为空", trigger: "blur" }
         ],
         sort: [
-          { required: true, message: '菜单顺序不能为空', trigger: 'blur' }
+          { required: true, message: "菜单顺序不能为空", trigger: "blur" }
         ],
         email: [
           {
-            type: 'email',
+            type: "email",
             message: "'请输入正确的邮箱地址",
-            trigger: ['blur', 'change']
+            trigger: ["blur", "change"]
           }
         ],
         phone: [
           {
             pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
-            message: '请输入正确的手机号码',
-            trigger: 'blur'
+            message: "请输入正确的手机号码",
+            trigger: "blur"
           }
         ]
       },
       statusOptions: [
-        { label: '正常', value: '0' },
-        { label: '停用', value: '1' }
+        { label: "正常", value: "0" },
+        { label: "停用", value: "1" }
       ]
-    }
+    };
   },
-  created() {
-    this.getList()
-    this.getOrganList()
+  mounted() {
+    this.getList();
+    this.getOrganList();
   },
   methods: {
     /** 查询部门列表 */
     getList() {
-      this.loading = true
+      this.loading = true;
       getDeptList(this.queryParams).then(response => {
-        this.deptList = response.data
-        this.loading = false
-      })
+        this.deptList = response.data;
+        this.loading = false;
+      });
     },
     // 查询用户
     getUsers() {
       listUser({
         pageSize: 999999
       }).then(response => {
-        this.users = response.data.list
-      })
+        this.users = response.data.list;
+      });
     },
     getOrganList() {
       queryEmployeeOrgan().then(res => {
-        this.organList = res.data || []
-      })
+        this.organList = res.data || [];
+      });
     },
     /** 转换部门数据结构 */
     normalizer(node) {
       if (node.children && !node.children.length) {
-        delete node.children
+        delete node.children;
       }
       return {
         id: node.deptId,
         label: node.deptName,
         children: node.children
-      }
+      };
     },
     /** 查询部门下拉树结构 */
     getTreeselect(e) {
       getDeptList().then(response => {
-        this.deptOptions = []
+        this.deptOptions = [];
 
-        if (e === 'update') {
-          const dept = { deptId: 0, deptName: '主类目', children: [], isDisabled: true }
-          dept.children = response.data
-          this.deptOptions.push(dept)
+        if (e === "update") {
+          const dept = {
+            deptId: 0,
+            deptName: "主类目",
+            children: [],
+            isDisabled: true
+          };
+          dept.children = response.data;
+          this.deptOptions.push(dept);
         } else {
-          const dept = { deptId: 0, deptName: '主类目', children: [] }
-          dept.children = response.data
-          this.deptOptions.push(dept)
+          const dept = { deptId: 0, deptName: "主类目", children: [] };
+          dept.children = response.data;
+          this.deptOptions.push(dept);
         }
-      })
+      });
     },
     // 取消按钮
     cancel() {
-      this.open = false
-      this.reset()
+      this.open = false;
+      this.reset();
     },
     // 表单重置
     reset() {
@@ -299,92 +354,92 @@ export default {
         phone: undefined,
         email: undefined,
         organId: null,
-        status: '0'
-      }
+        status: "0"
+      };
     },
     /** 搜索按钮操作 */
     handleQuery() {
-      this.getList()
+      this.getList();
     },
     /** 新增按钮操作 */
     handleAdd(row) {
-      this.getUsers()
-      this.reset()
-      this.getTreeselect('add')
+      this.getUsers();
+      this.reset();
+      this.getTreeselect("add");
       if (row !== undefined) {
-        this.form.parentId = row.deptId
+        this.form.parentId = row.deptId;
       }
-      this.open = true
-      this.title = '添加部门'
-      this.isEdit = false
+      this.open = true;
+      this.title = "添加部门";
+      this.isEdit = false;
     },
     /** 修改按钮操作 */
     handleUpdate(row) {
-      this.getUsers()
-      this.reset()
-      this.getTreeselect('update')
+      this.getUsers();
+      this.reset();
+      this.getTreeselect("update");
 
       getDept(row.deptId).then(response => {
-        this.form = response.data
+        this.form = response.data;
         if (this.form.leader === 0) {
-          this.form.leader = ''
+          this.form.leader = "";
         }
         if (this.form.organId === 0) {
-          this.form.organId = null
+          this.form.organId = null;
         }
-        this.open = true
-        this.title = '修改部门'
-        this.isEdit = true
-      })
+        this.open = true;
+        this.title = "修改部门";
+        this.isEdit = true;
+      });
     },
     /** 提交按钮 */
     submitForm: function() {
-      this.$refs['form'].validate(valid => {
+      this.$refs["form"].validate(valid => {
         if (valid) {
           if (this.form.deptId !== undefined) {
             updateDept(this.form).then(response => {
               if (response.code === 200) {
-                this.msgSuccess('修改成功')
-                this.open = false
-                this.getList()
+                this.msgSuccess("修改成功");
+                this.open = false;
+                this.getList();
               } else {
-                this.msgError(response.msg)
+                this.msgError(response.msg);
               }
-            })
+            });
           } else {
             addDept(this.form).then(response => {
               if (response.code === 200) {
-                this.msgSuccess('新增成功')
-                this.open = false
-                this.getList()
+                this.msgSuccess("新增成功");
+                this.open = false;
+                this.getList();
               } else {
-                this.msgError(response.msg)
+                this.msgError(response.msg);
               }
-            })
+            });
           }
         }
-      })
+      });
     },
     /** 删除按钮操作 */
     handleDelete(row) {
       this.$confirm(
         '是否确认删除名称为"' + row.deptName + '"的数据项?',
-        '警告',
+        "警告",
         {
-          confirmButtonText: '确定',
-          cancelButtonText: '取消',
-          type: 'warning'
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
         }
       )
         .then(function() {
-          return delDept(row.deptId)
+          return delDept(row.deptId);
         })
         .then(() => {
-          this.getList()
-          this.msgSuccess('删除成功')
+          this.getList();
+          this.msgSuccess("删除成功");
         })
-        .catch(function() {})
+        .catch(function() {});
     }
   }
-}
+};
 </script>

+ 173 - 76
src/views/system/loginlog/index.vue

@@ -1,7 +1,14 @@
 <template>
   <div class="app-container">
     <el-card class="box-card">
-      <el-form ref="queryForm" :model="queryParams" :inline="true" label-width="68px">
+      <save-form
+        ref="queryForm"
+        :model.sync="queryParams"
+        :inline="true"
+        label-width="68px"
+        @submit="handleQuery"
+        @reset="resetQuery"
+      >
         <el-form-item label="登录地址">
           <el-input
             v-model="queryParams.ipaddr"
@@ -24,10 +31,28 @@
         </el-form-item>
 
         <el-form-item>
-          <el-button type="primary" icon="el-icon-search" size="small" @click="handleQuery">搜索</el-button>
-          <el-button icon="el-icon-refresh" size="small" @click="resetQuery">重置</el-button>
+          <!-- <el-button
+            type="primary"
+            icon="el-icon-search"
+            size="small"
+            @click="handleQuery"
+            >搜索</el-button
+          >
+          <el-button icon="el-icon-refresh" size="small" @click="resetQuery"
+            >重置</el-button
+          > -->
+          <el-button
+            type="primary"
+            icon="el-icon-search"
+            size="small"
+            native-type="submit"
+            >搜索</el-button
+          >
+          <el-button icon="el-icon-refresh" size="small" native-type="reset"
+            >重置</el-button
+          >
         </el-form-item>
-      </el-form>
+      </save-form>
 
       <el-row :gutter="10" class="mb8">
         <el-col :span="1.5">
@@ -38,7 +63,8 @@
             size="mini"
             :disabled="multiple"
             @click="handleDelete"
-          >删除</el-button>
+            >删除</el-button
+          >
         </el-col>
         <el-col :span="1.5">
           <el-button
@@ -47,7 +73,8 @@
             icon="el-icon-delete"
             size="mini"
             @click="handleClean"
-          >清空</el-button>
+            >清空</el-button
+          >
         </el-col>
         <el-col :span="1.5">
           <el-button
@@ -56,20 +83,52 @@
             icon="el-icon-download"
             size="mini"
             @click="handleExport"
-          >导出</el-button>
+            >导出</el-button
+          >
         </el-col>
       </el-row>
 
-      <el-table v-loading="loading" border :data="list" @selection-change="handleSelectionChange">
+      <el-table
+        v-loading="loading"
+        border
+        :data="list"
+        @selection-change="handleSelectionChange"
+      >
         <el-table-column type="selection" width="55" align="center" />
-        <el-table-column label="编号" width="100" align="center" prop="infoId" />
-        <el-table-column label="用户名称" width="150" align="center" prop="username" />
-        <el-table-column label="登录地址" align="center" prop="ipaddr" width="130" :show-overflow-tooltip="true" />
+        <el-table-column
+          label="编号"
+          width="100"
+          align="center"
+          prop="infoId"
+        />
+        <el-table-column
+          label="用户名称"
+          width="150"
+          align="center"
+          prop="username"
+        />
+        <el-table-column
+          label="登录地址"
+          align="center"
+          prop="ipaddr"
+          width="130"
+          :show-overflow-tooltip="true"
+        />
         <el-table-column label="登录地点" align="center" prop="loginLocation" />
         <el-table-column label="浏览器" align="center" prop="browser" />
         <el-table-column label="操作系统" align="center" prop="os" />
-        <el-table-column label="操作信息" width="120" align="center" prop="msg" />
-        <el-table-column label="登录日期" align="center" prop="loginTime" width="180">
+        <el-table-column
+          label="操作信息"
+          width="120"
+          align="center"
+          prop="msg"
+        />
+        <el-table-column
+          label="登录日期"
+          align="center"
+          prop="loginTime"
+          width="180"
+        >
           <template slot-scope="scope">
             <span>{{ parseTime(scope.row.loginTime) }}</span>
           </template>
@@ -77,7 +136,7 @@
       </el-table>
 
       <pagination
-        v-show="total>0"
+        v-show="total > 0"
         :total="total"
         :page.sync="queryParams.pageIndex"
         :limit.sync="queryParams.pageSize"
@@ -88,11 +147,12 @@
 </template>
 
 <script>
-import { list, delLogininfor, cleanLogininfor } from '@/api/system/loginlog'
-import { formatJson } from '@/utils'
-
+import { list, delLogininfor, cleanLogininfor } from "@/api/system/loginlog";
+import { formatJson } from "@/utils";
+import SaveForm from "@/components/save-form";
 export default {
-  name: 'Logininfor',
+  name: "Logininfor",
+  components: { SaveForm },
   data() {
     return {
       // 遮罩层
@@ -115,93 +175,130 @@ export default {
         username: undefined,
         status: undefined
       }
-    }
+    };
   },
-  created() {
-    this.getList()
+  mounted() {
+    this.getList();
   },
   methods: {
     /** 查询登录日志列表 */
     getList() {
-      this.loading = true
-      list(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
-        this.list = response.data.list
-        this.total = response.data.count
-        this.loading = false
-      }
-      )
+      this.loading = true;
+      list(this.addDateRange(this.queryParams, this.dateRange)).then(
+        response => {
+          this.list = response.data.list;
+          this.total = response.data.count;
+          this.loading = false;
+        }
+      );
     },
     /** 搜索按钮操作 */
     handleQuery() {
-      this.queryParams.pageIndex = 1
-      this.getList()
+      this.queryParams.pageIndex = 1;
+      this.getList();
     },
     /** 重置按钮操作 */
     resetQuery() {
-      this.dateRange = []
-      this.resetForm('queryForm')
-      this.handleQuery()
+      this.queryParams = {
+        pageIndex: 1,
+        pageSize: 10,
+        ipaddr: undefined,
+        username: undefined,
+        status: undefined
+      };
+      this.dateRange = [];
+      this.resetForm("queryForm");
+      this.handleQuery();
     },
     // 多选框选中数据
     handleSelectionChange(selection) {
-      this.ids = selection.map(item => item.infoId)
-      this.multiple = !selection.length
+      this.ids = selection.map(item => item.infoId);
+      this.multiple = !selection.length;
     },
     /** 删除按钮操作 */
     handleDelete(row) {
-      const infoIds = row.infoId || this.ids
-      this.$confirm('是否确认删除访问编号为"' + infoIds + '"的数据项?', '警告', {
-        confirmButtonText: '确定',
-        cancelButtonText: '取消',
-        type: 'warning'
-      }).then(function() {
-        return delLogininfor(infoIds)
-      }).then(() => {
-        this.getList()
-        this.msgSuccess('删除成功')
-      }).catch(function() {})
+      const infoIds = row.infoId || this.ids;
+      this.$confirm(
+        '是否确认删除访问编号为"' + infoIds + '"的数据项?',
+        "警告",
+        {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }
+      )
+        .then(function() {
+          return delLogininfor(infoIds);
+        })
+        .then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        })
+        .catch(function() {});
     },
     /** 清空按钮操作 */
     handleClean() {
-      this.$confirm('是否确认清空所有登录日志数据项?', '警告', {
-        confirmButtonText: '确定',
-        cancelButtonText: '取消',
-        type: 'warning'
-      }).then(function() {
-        return cleanLogininfor()
-      }).then(response => {
-        if (response.code === 200) {
-          this.getList()
-          this.msgSuccess('清空成功')
-        }
-      }).catch(function() {})
+      this.$confirm("是否确认清空所有登录日志数据项?", "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      })
+        .then(function() {
+          return cleanLogininfor();
+        })
+        .then(response => {
+          if (response.code === 200) {
+            this.getList();
+            this.msgSuccess("清空成功");
+          }
+        })
+        .catch(function() {});
     },
     /** 导出按钮操作 */
     handleExport() {
       // const queryParams = this.queryParams
-      this.$confirm('是否确认导出所有操作日志数据项?', '警告', {
-        confirmButtonText: '确定',
-        cancelButtonText: '取消',
-        type: 'warning'
+      this.$confirm("是否确认导出所有操作日志数据项?", "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
       }).then(() => {
-        this.downloadLoading = true
-        import('@/vendor/Export2Excel').then(excel => {
-          const tHeader = ['编号', '用户名称', '登陆地址', '登陆地点', '浏览器', '操作系统', '登陆状态', '操作信息', '登陆日期']
-          const filterVal = ['infoId', 'username', 'ipaddr', 'loginLocation', 'browser', 'os', 'status', 'msg', 'loginTime']
-          const list = this.list
-          const data = formatJson(filterVal, list)
+        this.downloadLoading = true;
+        import("@/vendor/Export2Excel").then(excel => {
+          const tHeader = [
+            "编号",
+            "用户名称",
+            "登陆地址",
+            "登陆地点",
+            "浏览器",
+            "操作系统",
+            "登陆状态",
+            "操作信息",
+            "登陆日期"
+          ];
+          const filterVal = [
+            "infoId",
+            "username",
+            "ipaddr",
+            "loginLocation",
+            "browser",
+            "os",
+            "status",
+            "msg",
+            "loginTime"
+          ];
+          const list = this.list;
+          const data = formatJson(filterVal, list);
           excel.export_json_to_excel({
             header: tHeader,
             data,
-            filename: '登陆日志',
+            filename: "登陆日志",
             autoWidth: true, // Optional
-            bookType: 'xlsx' // Optional
-          })
-          this.downloadLoading = false
-        })
-      })
+            bookType: "xlsx" // Optional
+          });
+          this.downloadLoading = false;
+        });
+      });
     }
   }
-}
+};
 </script>
-

+ 196 - 108
src/views/system/menu/index.vue

@@ -1,7 +1,12 @@
 <template>
   <div class="app-container">
     <el-card class="box-card">
-      <el-form :inline="true">
+      <save-form
+        ref="searchForm"
+        :model.sync="queryParams"
+        :inline="true"
+        @submit="handleQuery"
+      >
         <el-form-item label="菜单名称">
           <el-input
             v-model="queryParams.title"
@@ -13,52 +18,84 @@
         </el-form-item>
 
         <el-form-item>
-          <el-button type="primary" icon="el-icon-search" size="small" @click="handleQuery">搜索</el-button>
+          <el-button
+            type="primary"
+            icon="el-icon-search"
+            size="small"
+            native-type="submit"
+            >搜索</el-button
+          >
           <el-button
             v-permisaction="['system:sysmenu:add']"
             type="primary"
             icon="el-icon-plus"
             size="small"
             @click="handleAdd"
-          >新增</el-button>
+            >新增</el-button
+          >
         </el-form-item>
-      </el-form>
+      </save-form>
 
       <el-table
         v-loading="loading"
         border
         :data="menuList"
         row-key="menuId"
-        :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
+        :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
       >
-        <el-table-column prop="title" label="菜单名称" :show-overflow-tooltip="true" width="180px" />
+        <el-table-column
+          prop="title"
+          label="菜单名称"
+          :show-overflow-tooltip="true"
+          width="180px"
+        />
         <el-table-column prop="icon" label="图标" align="center" width="100px">
           <template slot-scope="scope">
             <svg-icon :icon-class="scope.row.icon" />
           </template>
         </el-table-column>
         <el-table-column prop="sort" label="排序" width="60px" />
-        <el-table-column prop="permission" label="权限标识" :show-overflow-tooltip="true" />
+        <el-table-column
+          prop="permission"
+          label="权限标识"
+          :show-overflow-tooltip="true"
+        />
         <el-table-column prop="path" label="路径" :show-overflow-tooltip="true">
           <template slot-scope="scope">
-            <span v-if="scope.row.menuType=='A'">{{ scope.row.path }}</span>
+            <span v-if="scope.row.menuType == 'A'">{{ scope.row.path }}</span>
             <span v-else>{{ scope.row.component }}</span>
           </template>
         </el-table-column>
-        <el-table-column prop="visible" label="可见" :formatter="visibleFormat" width="80">
+        <el-table-column
+          prop="visible"
+          label="可见"
+          :formatter="visibleFormat"
+          width="80"
+        >
           <template slot-scope="scope">
             <el-tag
               :type="scope.row.visible === '1' ? 'danger' : 'success'"
               disable-transitions
-            >{{ visibleFormat(scope.row) }}</el-tag>
+              >{{ visibleFormat(scope.row) }}</el-tag
+            >
           </template>
         </el-table-column>
-        <el-table-column label="创建时间" align="center" prop="create_time" width="180">
+        <el-table-column
+          label="创建时间"
+          align="center"
+          prop="create_time"
+          width="180"
+        >
           <template slot-scope="scope">
             <span>{{ parseTime(scope.row.create_time) }}</span>
           </template>
         </el-table-column>
-        <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="180">
+        <el-table-column
+          label="操作"
+          align="center"
+          class-name="small-padding fixed-width"
+          width="180"
+        >
           <template slot-scope="scope">
             <el-button
               v-permisaction="['system:sysmenu:edit']"
@@ -66,21 +103,24 @@
               type="text"
               icon="el-icon-edit"
               @click="handleUpdate(scope.row)"
-            >编辑</el-button>
+              >编辑</el-button
+            >
             <el-button
               v-permisaction="['system:sysmenu:add']"
               size="mini"
               type="text"
               icon="el-icon-plus"
               @click="handleAdd(scope.row)"
-            >新增</el-button>
+              >新增</el-button
+            >
             <el-button
               v-permisaction="['system:sysmenu:remove']"
               size="mini"
               type="text"
               icon="el-icon-delete"
               @click="handleDelete(scope.row)"
-            >删除</el-button>
+              >删除</el-button
+            >
           </template>
         </el-table-column>
       </el-table>
@@ -107,7 +147,11 @@
           </el-col>
           <el-col :span="12">
             <el-form-item label="显示排序" prop="sort">
-              <el-input-number v-model="form.sort" controls-position="right" :min="0" />
+              <el-input-number
+                v-model="form.sort"
+                controls-position="right"
+                :min="0"
+              />
             </el-form-item>
           </el-col>
 
@@ -140,7 +184,12 @@
                 @show="$refs['iconSelect'].reset()"
               >
                 <IconSelect ref="iconSelect" @selected="selected" />
-                <el-input slot="reference" v-model="form.icon" placeholder="点击选择图标" readonly>
+                <el-input
+                  slot="reference"
+                  v-model="form.icon"
+                  placeholder="点击选择图标"
+                  readonly
+                >
                   <svg-icon
                     v-if="form.icon"
                     slot="prefix"
@@ -148,25 +197,40 @@
                     class="el-input__icon"
                     style="height: 32px;width: 16px;"
                   />
-                  <i v-else slot="prefix" class="el-icon-search el-input__icon" />
+                  <i
+                    v-else
+                    slot="prefix"
+                    class="el-icon-search el-input__icon"
+                  />
                 </el-input>
               </el-popover>
             </el-form-item>
           </el-col>
           <el-col :span="12">
-            <el-form-item v-if="form.menuType == 'M' || form.menuType == 'C'" label="路由名称" prop="menuName" style="width: 90%">
+            <el-form-item
+              v-if="form.menuType == 'M' || form.menuType == 'C'"
+              label="路由名称"
+              prop="menuName"
+              style="width: 90%"
+            >
               <el-input v-model="form.menuName" placeholder="请输入路由名称" />
             </el-form-item>
           </el-col>
 
-          <el-col v-if="form.menuType == 'M' || form.menuType == 'C'" :span="12">
+          <el-col
+            v-if="form.menuType == 'M' || form.menuType == 'C'"
+            :span="12"
+          >
             <el-form-item label="组件路径" prop="component" style="width: 90%">
               <el-input v-model="form.component" placeholder="请输入组件路径" />
             </el-form-item>
           </el-col>
 
           <el-col :span="12">
-            <el-form-item v-if="form.menuType == 'M' || form.menuType == 'C'" label="是否外链">
+            <el-form-item
+              v-if="form.menuType == 'M' || form.menuType == 'C'"
+              label="是否外链"
+            >
               <el-radio-group v-model="form.isFrame">
                 <el-radio label="0">是</el-radio>
                 <el-radio label="1">否</el-radio>
@@ -175,14 +239,27 @@
           </el-col>
 
           <el-col :span="12">
-            <el-form-item v-if="form.menuType != 'F'" label="路由地址" prop="path" style="width: 90%">
+            <el-form-item
+              v-if="form.menuType != 'F'"
+              label="路由地址"
+              prop="path"
+              style="width: 90%"
+            >
               <el-input v-model="form.path" placeholder="请输入路由地址" />
             </el-form-item>
           </el-col>
 
           <el-col :span="12">
-            <el-form-item v-if="form.menuType == 'F' || form.menuType == 'C'" label="权限标识" style="width: 90%">
-              <el-input v-model="form.permission" placeholder="请权限标识" maxlength="50" />
+            <el-form-item
+              v-if="form.menuType == 'F' || form.menuType == 'C'"
+              label="权限标识"
+              style="width: 90%"
+            >
+              <el-input
+                v-model="form.permission"
+                placeholder="请权限标识"
+                maxlength="50"
+              />
             </el-form-item>
           </el-col>
           <el-col :span="24">
@@ -192,7 +269,8 @@
                   v-for="dict in visibleOptions"
                   :key="dict.dictValue"
                   :label="dict.dictValue"
-                >{{ dict.dictLabel }}</el-radio>
+                  >{{ dict.dictLabel }}</el-radio
+                >
               </el-radio-group>
             </el-form-item>
           </el-col>
@@ -207,14 +285,20 @@
 </template>
 
 <script>
-import { listMenu, getMenu, delMenu, addMenu, updateMenu } from '@/api/system/menu'
-import Treeselect from '@riophae/vue-treeselect'
-import '@riophae/vue-treeselect/dist/vue-treeselect.css'
-import IconSelect from '@/components/IconSelect'
-
+import {
+  listMenu,
+  getMenu,
+  delMenu,
+  addMenu,
+  updateMenu
+} from "@/api/system/menu";
+import Treeselect from "@riophae/vue-treeselect";
+import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+import IconSelect from "@/components/IconSelect";
+import SaveForm from "@/components/save-form";
 export default {
-  name: 'Menu',
-  components: { Treeselect, IconSelect },
+  name: "Menu",
+  components: { Treeselect, IconSelect, SaveForm },
   data() {
     return {
       // 遮罩层
@@ -224,17 +308,20 @@ export default {
       // 菜单树选项
       menuOptions: [],
       // 弹出层标题
-      title: '',
+      title: "",
       // 是否显示弹出层
       open: false,
       // 菜单状态数据字典
-      visibleOptions: [{
-        dictValue: '0',
-        dictLabel: '显示'
-      }, {
-        dictValue: '1',
-        dictLabel: '隐藏'
-      }],
+      visibleOptions: [
+        {
+          dictValue: "0",
+          dictLabel: "显示"
+        },
+        {
+          dictValue: "1",
+          dictLabel: "隐藏"
+        }
+      ],
       // 查询参数
       queryParams: {
         title: undefined,
@@ -245,64 +332,62 @@ export default {
       // 表单校验
       rules: {
         title: [
-          { required: true, message: '菜单标题不能为空', trigger: 'blur' }
+          { required: true, message: "菜单标题不能为空", trigger: "blur" }
         ],
-        sort: [
-          { required: true, message: '菜单顺序不能为空', trigger: 'blur' }
-        ]
+        sort: [{ required: true, message: "菜单顺序不能为空", trigger: "blur" }]
       }
-    }
+    };
   },
-  created() {
-    this.getList()
+  mounted() {
+    this.getList();
   },
   methods: {
     // 选择图标
     selected(name) {
-      this.form.icon = name
+      this.form.icon = name;
     },
     /** 查询菜单列表 */
     getList() {
-      this.loading = true
+      this.loading = true;
       listMenu(this.queryParams).then(response => {
-        this.menuList = response.data
-        this.loading = false
-      })
+        this.menuList = response.data;
+        this.loading = false;
+      });
     },
     /** 转换菜单数据结构 */
     normalizer(node) {
       if (node.children && !node.children.length) {
-        delete node.children
+        delete node.children;
       }
       return {
         id: node.menuId,
         label: node.title,
         children: node.children
-      }
+      };
     },
     /** 查询菜单下拉树结构 */
     getTreeselect() {
       listMenu().then(response => {
-        this.menuOptions = []
-        const menu = { menuId: 0, title: '主类目', children: [] }
-        menu.children = response.data
-        this.menuOptions.push(menu)
-      })
+        this.menuOptions = [];
+        const menu = { menuId: 0, title: "主类目", children: [] };
+        menu.children = response.data;
+        this.menuOptions.push(menu);
+      });
     },
     // 菜单显示状态字典翻译
     visibleFormat(row) {
-      if (row.menuType === 'F') {
-        return '-- --'
-      } else if (row.visible === '1') {
-        return '隐藏'
-      } else if (row.visible === '0') {
-        return '可见'
+      if (row.menuType === "F") {
+        return "-- --";
+      } else if (row.visible === "1") {
+        return "隐藏";
+      } else if (row.visible === "0") {
+        return "可见";
       }
     },
     // 取消按钮
     cancel() {
-      this.open = false
-      this.reset()
+      this.open = false;
+      this.reset();
     },
     // 表单重置
     reset() {
@@ -311,79 +396,82 @@ export default {
         parentId: 0,
         menuName: undefined,
         icon: undefined,
-        menuType: 'M',
+        menuType: "M",
         sort: 0,
-        action: this.form.menuType === 'A' ? this.form.action : '',
-        isFrame: '1',
-        visible: '0'
-      }
-      this.resetForm('form')
+        action: this.form.menuType === "A" ? this.form.action : "",
+        isFrame: "1",
+        visible: "0"
+      };
+      this.resetForm("form");
     },
     /** 搜索按钮操作 */
     handleQuery() {
-      this.getList()
+      this.getList();
     },
     /** 新增按钮操作 */
     handleAdd(row) {
-      this.reset()
-      this.getTreeselect()
+      this.reset();
+      this.getTreeselect();
       if (row != null) {
-        this.form.parentId = row.menuId
+        this.form.parentId = row.menuId;
       }
-      this.open = true
-      this.title = '添加菜单'
+      this.open = true;
+      this.title = "添加菜单";
     },
     /** 修改按钮操作 */
     handleUpdate(row) {
-      this.reset()
-      this.getTreeselect()
+      this.reset();
+      this.getTreeselect();
       getMenu(row.menuId).then(response => {
-        this.form = response.data
-        this.open = true
-        this.title = '修改菜单'
-      })
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改菜单";
+      });
     },
     /** 提交按钮 */
     submitForm: function() {
-      this.$refs['form'].validate(valid => {
+      this.$refs["form"].validate(valid => {
         if (valid) {
           if (this.form.menuId !== undefined) {
             updateMenu(this.form).then(response => {
               if (response.code === 200) {
-                this.msgSuccess('修改成功')
-                this.open = false
-                this.getList()
+                this.msgSuccess("修改成功");
+                this.open = false;
+                this.getList();
               } else {
-                this.msgError(response.msg)
+                this.msgError(response.msg);
               }
-            })
+            });
           } else {
             addMenu(this.form).then(response => {
               if (response.code === 200) {
-                this.msgSuccess('新增成功')
-                this.open = false
-                this.getList()
+                this.msgSuccess("新增成功");
+                this.open = false;
+                this.getList();
               } else {
-                this.msgError(response.msg)
+                this.msgError(response.msg);
               }
-            })
+            });
           }
         }
-      })
+      });
     },
     /** 删除按钮操作 */
     handleDelete(row) {
-      this.$confirm('是否确认删除名称为"' + row.title + '"的数据项?', '警告', {
-        confirmButtonText: '确定',
-        cancelButtonText: '取消',
-        type: 'warning'
-      }).then(function() {
-        return delMenu(row.menuId)
-      }).then(() => {
-        this.getList()
-        this.msgSuccess('删除成功')
-      }).catch(function() {})
+      this.$confirm('是否确认删除名称为"' + row.title + '"的数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      })
+        .then(function() {
+          return delMenu(row.menuId);
+        })
+        .then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        })
+        .catch(function() {});
     }
   }
-}
+};
 </script>

+ 185 - 101
src/views/system/post/index.vue

@@ -1,7 +1,14 @@
 <template>
   <div class="app-container">
     <el-card class="box-card">
-      <el-form ref="queryForm" :model="queryParams" :inline="true" label-width="68px">
+      <save-form
+        ref="queryForm"
+        :model="queryParams"
+        :inline="true"
+        label-width="68px"
+        @submit="handleQuery"
+        @reset="resetQuery"
+      >
         <el-form-item label="岗位编码" prop="postCode">
           <el-input
             v-model="queryParams.postCode"
@@ -21,10 +28,20 @@
           />
         </el-form-item>
         <el-form-item>
-          <el-button type="primary" icon="el-icon-search" size="small" @click="handleQuery">搜索</el-button>
-          <el-button icon="el-icon-refresh" size="small" @click="resetQuery">重置</el-button>
+          <!-- <el-button type="primary" icon="el-icon-search" size="small" @click="handleQuery">搜索</el-button>
+          <el-button icon="el-icon-refresh" size="small" @click="resetQuery">重置</el-button> -->
+          <el-button
+            type="primary"
+            icon="el-icon-search"
+            size="small"
+            native-type="submit"
+            >搜索</el-button
+          >
+          <el-button icon="el-icon-refresh" size="small" native-type="reset"
+            >重置</el-button
+          >
         </el-form-item>
-      </el-form>
+      </save-form>
 
       <el-row :gutter="10" class="mb8">
         <el-col :span="1.5">
@@ -34,7 +51,8 @@
             icon="el-icon-plus"
             size="mini"
             @click="handleAdd"
-          >新增</el-button>
+            >新增</el-button
+          >
         </el-col>
         <el-col :span="1.5">
           <el-button
@@ -44,7 +62,8 @@
             size="mini"
             :disabled="single"
             @click="handleUpdate"
-          >编辑</el-button>
+            >编辑</el-button
+          >
         </el-col>
         <el-col :span="1.5">
           <el-button
@@ -54,7 +73,8 @@
             size="mini"
             :disabled="multiple"
             @click="handleDelete"
-          >删除</el-button>
+            >删除</el-button
+          >
         </el-col>
         <el-col :span="1.5">
           <el-button
@@ -63,13 +83,24 @@
             icon="el-icon-download"
             size="mini"
             @click="handleExport"
-          >导出</el-button>
+            >导出</el-button
+          >
         </el-col>
       </el-row>
 
-      <el-table v-loading="loading" border :data="postList" @selection-change="handleSelectionChange">
+      <el-table
+        v-loading="loading"
+        border
+        :data="postList"
+        @selection-change="handleSelectionChange"
+      >
         <el-table-column type="selection" width="55" align="center" />
-        <el-table-column label="岗位编号" width="80" align="center" prop="postId" />
+        <el-table-column
+          label="岗位编号"
+          width="80"
+          align="center"
+          prop="postId"
+        />
         <el-table-column label="岗位编码" align="center" prop="postCode" />
         <el-table-column label="岗位名称" align="center" prop="postName" />
         <el-table-column label="岗位排序" align="center" prop="sort" />
@@ -78,15 +109,25 @@
             <el-tag
               :type="scope.row.status === '1' ? 'danger' : 'success'"
               disable-transitions
-            >{{ scope.row.status === '1' ? '停用' : '正常' }}</el-tag>
+              >{{ scope.row.status === "1" ? "停用" : "正常" }}</el-tag
+            >
           </template>
         </el-table-column>
-        <el-table-column label="创建时间" align="center" prop="create_time" width="180">
+        <el-table-column
+          label="创建时间"
+          align="center"
+          prop="create_time"
+          width="180"
+        >
           <template slot-scope="scope">
             <span>{{ parseTime(scope.row.create_time) }}</span>
           </template>
         </el-table-column>
-        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <el-table-column
+          label="操作"
+          align="center"
+          class-name="small-padding fixed-width"
+        >
           <template slot-scope="scope">
             <el-button
               v-permisaction="['system:syspost:edit']"
@@ -94,20 +135,22 @@
               type="text"
               icon="el-icon-edit"
               @click="handleUpdate(scope.row)"
-            >编辑</el-button>
+              >编辑</el-button
+            >
             <el-button
               v-permisaction="['system:syspost:remove']"
               size="mini"
               type="text"
               icon="el-icon-delete"
               @click="handleDelete(scope.row)"
-            >删除</el-button>
+              >删除</el-button
+            >
           </template>
         </el-table-column>
       </el-table>
 
       <pagination
-        v-show="total>0"
+        v-show="total > 0"
         :total="total"
         :page.sync="queryParams.pageIndex"
         :limit.sync="queryParams.pageSize"
@@ -124,10 +167,18 @@
           <el-input v-model="form.postCode" placeholder="请输入编码名称" />
         </el-form-item>
         <el-form-item label="岗位顺序" prop="sort">
-          <el-input-number v-model="form.sort" controls-position="right" :min="0" />
+          <el-input-number
+            v-model="form.sort"
+            controls-position="right"
+            :min="0"
+          />
         </el-form-item>
         <el-form-item label="备注" prop="remark">
-          <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
+          <el-input
+            v-model="form.remark"
+            type="textarea"
+            placeholder="请输入内容"
+          />
         </el-form-item>
       </el-form>
       <div slot="footer" class="dialog-footer">
@@ -139,11 +190,18 @@
 </template>
 
 <script>
-import { listPost, getPost, delPost, addPost, updatePost } from '@/api/system/post'
-import { formatJson } from '@/utils'
-
+import {
+  listPost,
+  getPost,
+  delPost,
+  addPost,
+  updatePost
+} from "@/api/system/post";
+import { formatJson } from "@/utils";
+import SaveForm from "@/components/save-form";
 export default {
-  name: 'Post',
+  name: "Post",
+  components: { SaveForm },
   data() {
     return {
       // 遮罩层
@@ -159,7 +217,7 @@ export default {
       // 岗位表格数据
       postList: [],
       // 弹出层标题
-      title: '',
+      title: "",
       // 是否显示弹出层
       open: false,
       // 查询参数
@@ -175,34 +233,32 @@ export default {
       // 表单校验
       rules: {
         postName: [
-          { required: true, message: '岗位名称不能为空', trigger: 'blur' }
+          { required: true, message: "岗位名称不能为空", trigger: "blur" }
         ],
         postCode: [
-          { required: true, message: '岗位编码不能为空', trigger: 'blur' }
+          { required: true, message: "岗位编码不能为空", trigger: "blur" }
         ],
-        sort: [
-          { required: true, message: '岗位顺序不能为空', trigger: 'blur' }
-        ]
+        sort: [{ required: true, message: "岗位顺序不能为空", trigger: "blur" }]
       }
-    }
+    };
   },
-  created() {
-    this.getList()
+  mounted() {
+    this.getList();
   },
   methods: {
     /** 查询岗位列表 */
     getList() {
-      this.loading = true
+      this.loading = true;
       listPost(this.queryParams).then(response => {
-        this.postList = response.data.list
-        this.total = response.data.count
-        this.loading = false
-      })
+        this.postList = response.data.list;
+        this.total = response.data.count;
+        this.loading = false;
+      });
     },
     // 取消按钮
     cancel() {
-      this.open = false
-      this.reset()
+      this.open = false;
+      this.reset();
     },
     // 表单重置
     reset() {
@@ -211,111 +267,139 @@ export default {
         postCode: undefined,
         postName: undefined,
         sort: 0,
-        status: '0',
+        status: "0",
         remark: undefined
-      }
-      this.resetForm('form')
+      };
+      this.resetForm("form");
     },
     /** 搜索按钮操作 */
     handleQuery() {
-      this.queryParams.pageIndex = 1
-      this.getList()
+      this.queryParams.pageIndex = 1;
+      this.getList();
     },
     /** 重置按钮操作 */
     resetQuery() {
-      this.resetForm('queryForm')
-      this.handleQuery()
+      this.queryParams = {
+        pageIndex: 1,
+        pageSize: 10,
+        postCode: undefined,
+        postName: undefined,
+        status: undefined
+      };
+      this.resetForm("queryForm");
+      this.handleQuery();
     },
     // 多选框选中数据
     handleSelectionChange(selection) {
-      this.ids = selection.map(item => item.postId)
-      this.single = selection.length !== 1
-      this.multiple = !selection.length
+      this.ids = selection.map(item => item.postId);
+      this.single = selection.length !== 1;
+      this.multiple = !selection.length;
     },
     /** 新增按钮操作 */
     handleAdd() {
-      this.reset()
-      this.open = true
-      this.title = '添加岗位'
+      this.reset();
+      this.open = true;
+      this.title = "添加岗位";
     },
     /** 修改按钮操作 */
     handleUpdate(row) {
-      this.reset()
+      this.reset();
 
-      const postId = row.postId || this.ids
+      const postId = row.postId || this.ids;
       getPost(postId).then(response => {
-        this.form = response.data
-        this.open = true
-        this.title = '修改岗位'
-      })
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改岗位";
+      });
     },
     /** 提交按钮 */
     submitForm: function() {
-      this.$refs['form'].validate(valid => {
+      this.$refs["form"].validate(valid => {
         if (valid) {
           if (this.form.postId !== undefined) {
             updatePost(this.form).then(response => {
               if (response.code === 200) {
-                this.msgSuccess('修改成功')
-                this.open = false
-                this.getList()
+                this.msgSuccess("修改成功");
+                this.open = false;
+                this.getList();
               } else {
-                this.msgError(response.msg)
+                this.msgError(response.msg);
               }
-            })
+            });
           } else {
             addPost(this.form).then(response => {
               if (response.code === 200) {
-                this.msgSuccess('新增成功')
-                this.open = false
-                this.getList()
+                this.msgSuccess("新增成功");
+                this.open = false;
+                this.getList();
               } else {
-                this.msgError(response.msg)
+                this.msgError(response.msg);
               }
-            })
+            });
           }
         }
-      })
+      });
     },
     /** 删除按钮操作 */
     handleDelete(row) {
-      const postIds = row.postId || this.ids
-      this.$confirm('是否确认删除岗位编号为"' + postIds + '"的数据项?', '警告', {
-        confirmButtonText: '确定',
-        cancelButtonText: '取消',
-        type: 'warning'
-      }).then(function() {
-        return delPost(postIds)
-      }).then(() => {
-        this.getList()
-        this.msgSuccess('删除成功')
-      }).catch(function() {})
+      const postIds = row.postId || this.ids;
+      this.$confirm(
+        '是否确认删除岗位编号为"' + postIds + '"的数据项?',
+        "警告",
+        {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }
+      )
+        .then(function() {
+          return delPost(postIds);
+        })
+        .then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        })
+        .catch(function() {});
     },
     /** 导出按钮操作 */
     handleExport() {
       // const queryParams = this.queryParams
-      this.$confirm('是否确认导出所有岗位数据项?', '警告', {
-        confirmButtonText: '确定',
-        cancelButtonText: '取消',
-        type: 'warning'
-      }).then(() => {
-        this.downloadLoading = true
-      import('@/vendor/Export2Excel').then(excel => {
-        const tHeader = ['岗位编号', '岗位编码', '岗位名称', '排序', '创建时间']
-        const filterVal = ['postId', 'postCode', 'postName', 'sort', 'create_time']
-        const list = this.postList
-        const data = formatJson(filterVal, list)
-        excel.export_json_to_excel({
-          header: tHeader,
-          data,
-          filename: '岗位管理',
-          autoWidth: true, // Optional
-          bookType: 'xlsx' // Optional
-        })
-        this.downloadLoading = false
+      this.$confirm("是否确认导出所有岗位数据项?", "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
       })
-      }).catch(function() {})
+        .then(() => {
+          this.downloadLoading = true;
+          import("@/vendor/Export2Excel").then(excel => {
+            const tHeader = [
+              "岗位编号",
+              "岗位编码",
+              "岗位名称",
+              "排序",
+              "创建时间"
+            ];
+            const filterVal = [
+              "postId",
+              "postCode",
+              "postName",
+              "sort",
+              "create_time"
+            ];
+            const list = this.postList;
+            const data = formatJson(filterVal, list);
+            excel.export_json_to_excel({
+              header: tHeader,
+              data,
+              filename: "岗位管理",
+              autoWidth: true, // Optional
+              bookType: "xlsx" // Optional
+            });
+            this.downloadLoading = false;
+          });
+        })
+        .catch(function() {});
     }
   }
-}
+};
 </script>

+ 262 - 157
src/views/system/role/index.vue

@@ -1,7 +1,13 @@
 <template>
   <div class="app-container">
     <el-card class="box-card">
-      <el-form ref="queryForm" :model="queryParams" :inline="true">
+      <save-form
+        ref="queryForm"
+        :model="queryParams"
+        :inline="true"
+        @submit="handleQuery"
+        @reset="resetQuery"
+      >
         <el-form-item label="角色名称" prop="roleName">
           <el-input
             v-model="queryParams.roleName"
@@ -35,10 +41,20 @@
         />
       </el-form-item> -->
         <el-form-item>
-          <el-button type="primary" icon="el-icon-search" size="small" @click="handleQuery">搜索</el-button>
-          <el-button icon="el-icon-refresh" size="small" @click="resetQuery">重置</el-button>
+          <!-- <el-button type="primary" icon="el-icon-search" size="small" @click="handleQuery">搜索</el-button>
+          <el-button icon="el-icon-refresh" size="small" @click="resetQuery">重置</el-button> -->
+          <el-button
+            type="primary"
+            icon="el-icon-search"
+            size="small"
+            native-type="submit"
+            >搜索</el-button
+          >
+          <el-button icon="el-icon-refresh" size="small" native-type="reset"
+            >重置</el-button
+          >
         </el-form-item>
-      </el-form>
+      </save-form>
 
       <el-row :gutter="10" class="mb8">
         <el-col :span="1.5">
@@ -48,7 +64,8 @@
             icon="el-icon-plus"
             size="mini"
             @click="handleAdd"
-          >新增</el-button>
+            >新增</el-button
+          >
         </el-col>
         <el-col :span="1.5">
           <el-button
@@ -58,7 +75,8 @@
             size="mini"
             :disabled="single"
             @click="handleUpdate"
-          >编辑</el-button>
+            >编辑</el-button
+          >
         </el-col>
         <el-col :span="1.5">
           <el-button
@@ -68,7 +86,8 @@
             size="mini"
             :disabled="multiple"
             @click="handleDelete"
-          >删除</el-button>
+            >删除</el-button
+          >
         </el-col>
         <el-col :span="1.5">
           <el-button
@@ -77,15 +96,31 @@
             icon="el-icon-download"
             size="mini"
             @click="handleExport"
-          >导出</el-button>
+            >导出</el-button
+          >
         </el-col>
       </el-row>
 
-      <el-table v-loading="loading" border :data="roleList" @selection-change="handleSelectionChange">
+      <el-table
+        v-loading="loading"
+        border
+        :data="roleList"
+        @selection-change="handleSelectionChange"
+      >
         <el-table-column type="selection" width="55" align="center" />
         <el-table-column label="角色编号" prop="roleId" width="120" />
-        <el-table-column label="角色名称" prop="roleName" :show-overflow-tooltip="true" width="150" />
-        <el-table-column label="权限字符" prop="roleKey" :show-overflow-tooltip="true" width="150" />
+        <el-table-column
+          label="角色名称"
+          prop="roleName"
+          :show-overflow-tooltip="true"
+          width="150"
+        />
+        <el-table-column
+          label="权限字符"
+          prop="roleKey"
+          :show-overflow-tooltip="true"
+          width="150"
+        />
         <el-table-column label="显示顺序" prop="roleSort" width="100" />
         <el-table-column label="状态" align="center" width="100">
           <template slot-scope="scope">
@@ -97,12 +132,21 @@
             />
           </template>
         </el-table-column>
-        <el-table-column label="创建时间" align="center" prop="create_time" width="180">
+        <el-table-column
+          label="创建时间"
+          align="center"
+          prop="create_time"
+          width="180"
+        >
           <template slot-scope="scope">
             <span>{{ parseTime(scope.row.create_time) }}</span>
           </template>
         </el-table-column>
-        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <el-table-column
+          label="操作"
+          align="center"
+          class-name="small-padding fixed-width"
+        >
           <template slot-scope="scope">
             <el-button
               v-permisaction="['system:sysrole:edit']"
@@ -110,20 +154,22 @@
               type="text"
               icon="el-icon-edit"
               @click="handleUpdate(scope.row)"
-            >编辑</el-button>
+              >编辑</el-button
+            >
             <el-button
               v-permisaction="['system:sysrole:remove']"
               size="mini"
               type="text"
               icon="el-icon-delete"
               @click="handleDelete(scope.row)"
-            >删除</el-button>
+              >删除</el-button
+            >
           </template>
         </el-table-column>
       </el-table>
 
       <pagination
-        v-show="total>0"
+        v-show="total > 0"
         :total="total"
         :page.sync="queryParams.pageIndex"
         :limit.sync="queryParams.pageSize"
@@ -134,13 +180,25 @@
       <el-dialog :title="title" :visible.sync="open" width="500px">
         <el-form ref="form" :model="form" :rules="rules" label-width="80px">
           <el-form-item label="角色名称" prop="roleName">
-            <el-input v-model="form.roleName" placeholder="请输入角色名称" :disabled="isEdit" />
+            <el-input
+              v-model="form.roleName"
+              placeholder="请输入角色名称"
+              :disabled="isEdit"
+            />
           </el-form-item>
           <el-form-item label="权限字符" prop="roleKey">
-            <el-input v-model="form.roleKey" placeholder="请输入权限字符" :disabled="isEdit" />
+            <el-input
+              v-model="form.roleKey"
+              placeholder="请输入权限字符"
+              :disabled="isEdit"
+            />
           </el-form-item>
           <el-form-item label="角色顺序" prop="roleSort">
-            <el-input-number v-model="form.roleSort" controls-position="right" :min="0" />
+            <el-input-number
+              v-model="form.roleSort"
+              controls-position="right"
+              :min="0"
+            />
           </el-form-item>
           <el-form-item label="菜单权限">
             <el-tree
@@ -153,7 +211,11 @@
             />
           </el-form-item>
           <el-form-item label="备注">
-            <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
+            <el-input
+              v-model="form.remark"
+              type="textarea"
+              placeholder="请输入内容"
+            />
           </el-form-item>
         </el-form>
         <div slot="footer" class="dialog-footer">
@@ -203,13 +265,28 @@
 </template>
 
 <script>
-import { listRole, getRole, delRole, addRole, updateRole, dataScope, changeRoleStatus } from '@/api/system/role'
-import { treeselect as menuTreeselect, roleMenuTreeselect } from '@/api/system/menu'
-import { treeselect as deptTreeselect, roleDeptTreeselect } from '@/api/system/dept'
-import { formatJson } from '@/utils'
-
+import {
+  listRole,
+  getRole,
+  delRole,
+  addRole,
+  updateRole,
+  dataScope,
+  changeRoleStatus
+} from "@/api/system/role";
+import {
+  treeselect as menuTreeselect,
+  roleMenuTreeselect
+} from "@/api/system/menu";
+import {
+  treeselect as deptTreeselect,
+  roleDeptTreeselect
+} from "@/api/system/dept";
+import { formatJson } from "@/utils";
+import SaveForm from "@/components/save-form";
 export default {
-  name: 'Role',
+  name: "Role",
+  components: { SaveForm },
   data() {
     return {
       // 遮罩层
@@ -225,7 +302,7 @@ export default {
       // 角色表格数据
       roleList: [],
       // 弹出层标题
-      title: '',
+      title: "",
       // 是否显示弹出层
       open: false,
       // 是否显示弹出层(数据权限)
@@ -236,24 +313,24 @@ export default {
       // 数据范围选项
       dataScopeOptions: [
         {
-          value: '1',
-          label: '全部数据权限'
+          value: "1",
+          label: "全部数据权限"
         },
         {
-          value: '2',
-          label: '自定数据权限'
+          value: "2",
+          label: "自定数据权限"
         },
         {
-          value: '3',
-          label: '本部门数据权限'
+          value: "3",
+          label: "本部门数据权限"
         },
         {
-          value: '4',
-          label: '本部门及以下数据权限'
+          value: "4",
+          label: "本部门及以下数据权限"
         },
         {
-          value: '5',
-          label: '仅本人数据权限'
+          value: "5",
+          label: "仅本人数据权限"
         }
       ],
       // 菜单列表
@@ -271,248 +348,276 @@ export default {
       // 表单参数
       form: {},
       defaultProps: {
-        children: 'children',
-        label: 'label'
+        children: "children",
+        label: "label"
       },
       // 表单校验
       rules: {
         roleName: [
-          { required: true, message: '角色名称不能为空', trigger: 'blur' }
+          { required: true, message: "角色名称不能为空", trigger: "blur" }
         ],
         roleKey: [
-          { required: true, message: '权限字符不能为空', trigger: 'blur' }
+          { required: true, message: "权限字符不能为空", trigger: "blur" }
         ],
         roleSort: [
-          { required: true, message: '角色顺序不能为空', trigger: 'blur' }
+          { required: true, message: "角色顺序不能为空", trigger: "blur" }
         ]
       }
-    }
+    };
   },
-  created() {
-    this.getList()
+  mounted() {
+    this.getList();
   },
   methods: {
     /** 查询角色列表 */
     getList() {
-      this.loading = true
+      this.loading = true;
       listRole(this.addDateRange(this.queryParams, this.dateRange)).then(
         response => {
-          this.roleList = response.data.list
-          this.total = response.data.count
-          this.loading = false
+          this.roleList = response.data.list;
+          this.total = response.data.count;
+          this.loading = false;
         }
-      )
+      );
     },
     /** 查询菜单树结构 */
     getMenuTreeselect() {
       menuTreeselect().then(response => {
-        this.menuOptions = response.data
-      })
+        this.menuOptions = response.data;
+      });
     },
     /** 查询部门树结构 */
     getDeptTreeselect() {
       deptTreeselect().then(response => {
-        this.deptOptions = response.data.list
-      })
+        this.deptOptions = response.data.list;
+      });
     },
     // 所有菜单节点数据
     getMenuAllCheckedKeys() {
       // 目前被选中的菜单节点
-      const checkedKeys = this.$refs.menu.getHalfCheckedKeys()
+      const checkedKeys = this.$refs.menu.getHalfCheckedKeys();
       // 半选中的菜单节点
-      const halfCheckedKeys = this.$refs.menu.getCheckedKeys()
-      checkedKeys.unshift.apply(checkedKeys, halfCheckedKeys)
-      return checkedKeys
+      const halfCheckedKeys = this.$refs.menu.getCheckedKeys();
+      checkedKeys.unshift.apply(checkedKeys, halfCheckedKeys);
+      return checkedKeys;
     },
     // 所有部门节点数据
     getDeptAllCheckedKeys() {
       // 目前被选中的部门节点
-      const checkedKeys = this.$refs.dept.getCheckedKeys()
+      const checkedKeys = this.$refs.dept.getCheckedKeys();
       // 半选中的部门节点
       // const halfCheckedKeys = this.$refs.dept.getCheckedKeys()
       // checkedKeys.unshift.apply(checkedKeys, halfCheckedKeys)
-      return checkedKeys
+      return checkedKeys;
     },
     /** 根据角色ID查询菜单树结构 */
     getRoleMenuTreeselect(roleId) {
       roleMenuTreeselect(roleId).then(response => {
-        this.menuOptions = response.menus
+        this.menuOptions = response.menus;
         this.$nextTick(() => {
-          this.$refs.menu.setCheckedKeys(response.checkedKeys)
-        })
-      })
+          this.$refs.menu.setCheckedKeys(response.checkedKeys);
+        });
+      });
     },
     /** 根据角色ID查询部门树结构 */
     getRoleDeptTreeselect(roleId) {
       roleDeptTreeselect(roleId).then(response => {
-        this.deptOptions = response.depts
+        this.deptOptions = response.depts;
         this.$nextTick(() => {
-          this.$refs.dept.setCheckedKeys(response.checkedKeys)
-        })
-      })
+          this.$refs.dept.setCheckedKeys(response.checkedKeys);
+        });
+      });
     },
     // 角色状态修改
     handleStatusChange(row) {
-      const text = row.status === '0' ? '启用' : '停用'
-      this.$confirm('确认要"' + text + '""' + row.roleName + '"角色吗?', '警告', {
-        confirmButtonText: '确定',
-        cancelButtonText: '取消',
-        type: 'warning'
-      }).then(function() {
-        return changeRoleStatus(row.roleId, row.status)
-      }).then(() => {
-        this.msgSuccess(text + '成功')
-      }).catch(function() {
-        row.status = row.status === '0' ? '1' : '0'
-      })
+      const text = row.status === "0" ? "启用" : "停用";
+      this.$confirm(
+        '确认要"' + text + '""' + row.roleName + '"角色吗?',
+        "警告",
+        {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }
+      )
+        .then(function() {
+          return changeRoleStatus(row.roleId, row.status);
+        })
+        .then(() => {
+          this.msgSuccess(text + "成功");
+        })
+        .catch(function() {
+          row.status = row.status === "0" ? "1" : "0";
+        });
     },
     // 取消按钮
     cancel() {
-      this.open = false
-      this.reset()
+      this.open = false;
+      this.reset();
     },
     // 取消按钮(数据权限)
     cancelDataScope() {
-      this.openDataScope = false
-      this.reset()
+      this.openDataScope = false;
+      this.reset();
     },
     // 表单重置
     reset() {
       if (this.$refs.menu !== undefined) {
-        this.$refs.menu.setCheckedKeys([])
+        this.$refs.menu.setCheckedKeys([]);
       }
       this.form = {
         roleId: undefined,
         roleName: undefined,
         roleKey: undefined,
         roleSort: 0,
-        status: '0',
+        status: "0",
         menuIds: [],
         deptIds: [],
         remark: undefined
-      }
-      this.resetForm('form')
+      };
+      this.resetForm("form");
     },
     /** 搜索按钮操作 */
     handleQuery() {
-      this.queryParams.pageIndex = 1
-      this.getList()
+      this.queryParams.pageIndex = 1;
+      this.getList();
     },
     /** 重置按钮操作 */
     resetQuery() {
-      this.dateRange = []
-      this.resetForm('queryForm')
-      this.handleQuery()
+      this.dateRange = [];
+      this.resetForm("queryForm");
+      this.handleQuery();
     },
     // 多选框选中数据
     handleSelectionChange(selection) {
-      this.ids = selection.map(item => item.roleId)
-      this.single = selection.length !== 1
-      this.multiple = !selection.length
+      this.ids = selection.map(item => item.roleId);
+      this.single = selection.length !== 1;
+      this.multiple = !selection.length;
     },
     /** 新增按钮操作 */
     handleAdd() {
-      this.reset()
-      this.getMenuTreeselect()
-      this.open = true
-      this.title = '添加角色'
-      this.isEdit = false
+      this.reset();
+      this.getMenuTreeselect();
+      this.open = true;
+      this.title = "添加角色";
+      this.isEdit = false;
     },
     /** 修改按钮操作 */
     handleUpdate(row) {
-      this.reset()
-      const roleId = row.roleId || this.ids
+      this.reset();
+      const roleId = row.roleId || this.ids;
       getRole(roleId).then(response => {
-        this.form = response.data
-        this.open = true
-        this.title = '修改角色'
-        this.isEdit = true
-        this.getRoleMenuTreeselect(roleId)
-      })
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改角色";
+        this.isEdit = true;
+        this.getRoleMenuTreeselect(roleId);
+      });
     },
     /** 提交按钮 */
     submitForm: function() {
-      this.$refs['form'].validate(valid => {
+      this.$refs["form"].validate(valid => {
         if (valid) {
           if (this.form.roleId !== undefined) {
-            this.form.menuIds = this.getMenuAllCheckedKeys()
+            this.form.menuIds = this.getMenuAllCheckedKeys();
             updateRole(this.form).then(response => {
               if (response.code === 200) {
-                this.msgSuccess('修改成功')
-                this.open = false
-                this.getList()
+                this.msgSuccess("修改成功");
+                this.open = false;
+                this.getList();
               } else {
-                this.msgError(response.msg)
+                this.msgError(response.msg);
               }
-            })
+            });
           } else {
-            this.form.menuIds = this.getMenuAllCheckedKeys()
+            this.form.menuIds = this.getMenuAllCheckedKeys();
             addRole(this.form).then(response => {
               if (response.code === 200) {
-                this.msgSuccess('新增成功')
-                this.open = false
-                this.getList()
+                this.msgSuccess("新增成功");
+                this.open = false;
+                this.getList();
               } else {
-                this.msgError(response.msg)
+                this.msgError(response.msg);
               }
-            })
+            });
           }
         }
-      })
+      });
     },
     /** 提交按钮(数据权限) */
     submitDataScope: function() {
       if (this.form.roleId !== undefined) {
-        this.form.deptIds = this.getDeptAllCheckedKeys()
+        this.form.deptIds = this.getDeptAllCheckedKeys();
         dataScope(this.form).then(response => {
           if (response.code === 200) {
-            this.msgSuccess('修改成功')
-            this.openDataScope = false
-            this.getList()
+            this.msgSuccess("修改成功");
+            this.openDataScope = false;
+            this.getList();
           } else {
-            this.msgError(response.msg)
+            this.msgError(response.msg);
           }
-        })
+        });
       }
     },
     /** 删除按钮操作 */
     handleDelete(row) {
-      const roleIds = row.roleId || this.ids
-      this.$confirm('是否确认删除角色编号为"' + roleIds + '"的数据项?', '警告', {
-        confirmButtonText: '确定',
-        cancelButtonText: '取消',
-        type: 'warning'
-      }).then(function() {
-        return delRole(roleIds)
-      }).then(() => {
-        this.getList()
-        this.msgSuccess('删除成功')
-      }).catch(function() {})
+      const roleIds = row.roleId || this.ids;
+      this.$confirm(
+        '是否确认删除角色编号为"' + roleIds + '"的数据项?',
+        "警告",
+        {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }
+      )
+        .then(function() {
+          return delRole(roleIds);
+        })
+        .then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        })
+        .catch(function() {});
     },
     /** 导出按钮操作 */
     handleExport() {
-      this.$confirm('是否确认导出所有角色数据项?', '警告', {
-        confirmButtonText: '确定',
-        cancelButtonText: '取消',
-        type: 'warning'
+      this.$confirm("是否确认导出所有角色数据项?", "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
       }).then(() => {
-        this.downloadLoading = true
-        import('@/vendor/Export2Excel').then(excel => {
-          const tHeader = ['角色编号', '角色名称', '权限字符', '显示顺序', '状态', '创建时间']
-          const filterVal = ['roleId', 'roleName', 'roleKey', 'roleSort', 'status', 'create_time']
-          const list = this.roleList
-          const data = formatJson(filterVal, list)
+        this.downloadLoading = true;
+        import("@/vendor/Export2Excel").then(excel => {
+          const tHeader = [
+            "角色编号",
+            "角色名称",
+            "权限字符",
+            "显示顺序",
+            "状态",
+            "创建时间"
+          ];
+          const filterVal = [
+            "roleId",
+            "roleName",
+            "roleKey",
+            "roleSort",
+            "status",
+            "create_time"
+          ];
+          const list = this.roleList;
+          const data = formatJson(filterVal, list);
           excel.export_json_to_excel({
             header: tHeader,
             data,
-            filename: '角色管理',
+            filename: "角色管理",
             autoWidth: true, // Optional
-            bookType: 'xlsx' // Optional
-          })
-          this.downloadLoading = false
-        })
-      })
+            bookType: "xlsx" // Optional
+          });
+          this.downloadLoading = false;
+        });
+      });
     }
   }
-}
+};
 </script>

+ 351 - 192
src/views/system/sysuser/index.vue

@@ -30,7 +30,14 @@
       <!--用户数据-->
       <el-col :span="20" :xs="24">
         <el-card class="box-card">
-          <el-form ref="queryForm" :model="queryParams" :inline="true" label-width="68px">
+          <save-form
+            ref="queryForm"
+            :model="queryParams"
+            :inline="true"
+            label-width="68px"
+            @submit="handleQuery"
+            @reset="resetQuery"
+          >
             <el-form-item label="用户名称" prop="username">
               <el-input
                 v-model="queryParams.username"
@@ -52,10 +59,18 @@
               />
             </el-form-item>
             <el-form-item>
-              <el-button type="primary" icon="el-icon-search" size="small" @click="handleQuery">搜索</el-button>
-              <el-button icon="el-icon-refresh" size="small" @click="resetQuery">重置</el-button>
+              <el-button
+                type="primary"
+                icon="el-icon-search"
+                size="small"
+                native-type="submit"
+                >搜索</el-button
+              >
+              <el-button icon="el-icon-refresh" size="small" native-type="reset"
+                >重置</el-button
+              >
             </el-form-item>
-          </el-form>
+          </save-form>
 
           <el-row :gutter="10" class="mb8">
             <!-- <el-col :span="1.5">
@@ -96,11 +111,36 @@
             @selection-change="handleSelectionChange"
           >
             <el-table-column type="selection" width="45" align="center" />
-            <el-table-column label="编号" width="50" 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="deptName" :show-overflow-tooltip="true" />
-            <el-table-column label="手机号码" align="center" prop="phone" width="120" />
+            <el-table-column
+              label="编号"
+              width="50"
+              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="deptName"
+              :show-overflow-tooltip="true"
+            />
+            <el-table-column
+              label="手机号码"
+              align="center"
+              prop="phone"
+              width="120"
+            />
             <el-table-column label="状态" width="68" align="center">
               <template slot-scope="scope">
                 <el-switch
@@ -111,7 +151,12 @@
                 />
               </template>
             </el-table-column>
-            <el-table-column label="创建时间" align="center" prop="create_time" width="165">
+            <el-table-column
+              label="创建时间"
+              align="center"
+              prop="create_time"
+              width="165"
+            >
               <template slot-scope="scope">
                 <span>{{ parseTime(scope.row.create_time) }}</span>
               </template>
@@ -129,14 +174,16 @@
                   type="text"
                   icon="el-icon-edit"
                   @click="handleUpdate(scope.row)"
-                >修改</el-button>
+                  >修改</el-button
+                >
                 <el-button
                   v-permisaction="['system:sysuser:changeAssignUser']"
                   size="mini"
                   type="text"
                   icon="el-icon-key"
                   @click="handleQuit(scope.row)"
-                >离职交接</el-button>
+                  >离职交接</el-button
+                >
                 <!-- <el-button
                   v-if="scope.row.username !== 'admin'"
                   v-permisaction="['system:sysuser:remove']"
@@ -157,7 +204,7 @@
           </el-table>
 
           <pagination
-            v-show="total>0"
+            v-show="total > 0"
             :total="total"
             :page.sync="queryParams.pageIndex"
             :limit.sync="queryParams.pageSize"
@@ -173,22 +220,49 @@
         <el-row>
           <el-col :span="12">
             <el-form-item label="用户名称" prop="username" style="width: 90%">
-              <el-input v-model="form.username" disabled clearable placeholder="请输入用户名称" />
+              <el-input
+                v-model="form.username"
+                disabled
+                clearable
+                placeholder="请输入用户名称"
+              />
             </el-form-item>
           </el-col>
           <el-col :span="12">
             <el-form-item label="用户昵称" prop="nickName" style="width: 90%">
-              <el-input v-model="form.nickName" disabled clearable placeholder="请输入用户昵称" />
+              <el-input
+                v-model="form.nickName"
+                disabled
+                clearable
+                placeholder="请输入用户昵称"
+              />
             </el-form-item>
           </el-col>
           <el-col :span="12">
-            <el-form-item v-if="form.userId == undefined" label="用户密码" prop="password" style="width: 90%">
-              <el-input v-model="form.password" disabled clearable placeholder="请输入用户密码" type="password" />
+            <el-form-item
+              v-if="form.userId == undefined"
+              label="用户密码"
+              prop="password"
+              style="width: 90%"
+            >
+              <el-input
+                v-model="form.password"
+                disabled
+                clearable
+                placeholder="请输入用户密码"
+                type="password"
+              />
             </el-form-item>
           </el-col>
           <el-col :span="12">
             <el-form-item label="手机号码" prop="phone" style="width: 90%">
-              <el-input v-model="form.phone" disabled clearable placeholder="请输入手机号码" maxlength="11" />
+              <el-input
+                v-model="form.phone"
+                disabled
+                clearable
+                placeholder="请输入手机号码"
+                maxlength="11"
+              />
             </el-form-item>
           </el-col>
           <!-- <el-col :span="12">
@@ -198,7 +272,14 @@
           </el-col> -->
           <el-col :span="12">
             <el-form-item label="角色" style="width: 90%">
-              <el-select v-model="form.roleId" filterable clearable placeholder="请选择" style="width: 100%" @change="$forceUpdate()">
+              <el-select
+                v-model="form.roleId"
+                filterable
+                clearable
+                placeholder="请选择"
+                style="width: 100%"
+                @change="$forceUpdate()"
+              >
                 <el-option
                   v-for="item in roleOptions"
                   :key="item.roleId"
@@ -224,7 +305,16 @@
           </el-col>
           <el-col :span="12">
             <el-form-item label="岗位" style="width: 90%">
-              <el-select v-model="form.postIds" filterable clearable disabled multiple placeholder="请选择" style="width: 100%" @change="$forceUpdate()">
+              <el-select
+                v-model="form.postIds"
+                filterable
+                clearable
+                disabled
+                multiple
+                placeholder="请选择"
+                style="width: 100%"
+                @change="$forceUpdate()"
+              >
                 <el-option
                   v-for="item in postOptions"
                   :key="item.postId"
@@ -251,7 +341,13 @@
           </el-col>
           <el-col :span="24">
             <el-form-item label="备注" style="width: 95%">
-              <el-input v-model="form.remark" disabled clearable type="textarea" placeholder="请输入内容" />
+              <el-input
+                v-model="form.remark"
+                disabled
+                clearable
+                type="textarea"
+                placeholder="请输入内容"
+              />
             </el-form-item>
           </el-col>
         </el-row>
@@ -264,12 +360,28 @@
 
     <!-- 添加或修改参数配置对话框 -->
     <el-dialog title="离职交接" :visible.sync="quitOpen" width="400px">
-      <el-form ref="quitForm" :model="quitForm" :rules="quitRules" label-width="80px">
+      <el-form
+        ref="quitForm"
+        :model="quitForm"
+        :rules="quitRules"
+        label-width="80px"
+      >
         <el-row>
           <el-col :span="24">
             <el-form-item label="交接人" prop="toUserId" style="width: 95%">
-              <el-select v-model="quitForm.toUserId" filterable clearable placeholder="请选择交接人" style="width: 100%">
-                <el-option v-for="user in users" :key="user.userId" :label="user.nickName===''?user.username:user.nickName" :value="user.userId" />
+              <el-select
+                v-model="quitForm.toUserId"
+                filterable
+                clearable
+                placeholder="请选择交接人"
+                style="width: 100%"
+              >
+                <el-option
+                  v-for="user in users"
+                  :key="user.userId"
+                  :label="user.nickName === '' ? user.username : user.nickName"
+                  :value="user.userId"
+                />
               </el-select>
             </el-form-item>
           </el-col>
@@ -301,10 +413,16 @@
           <em>点击上传</em>
         </div>
         <div slot="tip" class="el-upload__tip">
-          <el-checkbox v-model="upload.updateSupport" />是否更新已经存在的用户数据
-          <el-link type="info" style="font-size:12px" @click="importTemplate">下载模板</el-link>
+          <el-checkbox
+            v-model="upload.updateSupport"
+          />是否更新已经存在的用户数据
+          <el-link type="info" style="font-size:12px" @click="importTemplate"
+            >下载模板</el-link
+          >
+        </div>
+        <div slot="tip" class="el-upload__tip" style="color:red">
+          提示:仅允许导入“xls”或“xlsx”格式文件!
         </div>
-        <div slot="tip" class="el-upload__tip" style="color:red">提示:仅允许导入“xls”或“xlsx”格式文件!</div>
       </el-upload>
       <div slot="footer" class="dialog-footer">
         <el-button type="primary" @click="submitFileForm">确 定</el-button>
@@ -315,15 +433,28 @@
 </template>
 
 <script>
-import { listUser, getUser, delUser, changeAssignUser, addUser, updateUser, exportUser, resetUserPwd, changeUserStatus, importTemplate, getUserInit } from '@/api/system/sysuser'
-import { getToken } from '@/utils/auth'
-import { treeselect } from '@/api/system/dept'
-import Treeselect from '@riophae/vue-treeselect'
-import '@riophae/vue-treeselect/dist/vue-treeselect.css'
-import load from '@/utils/loading'
+import {
+  listUser,
+  getUser,
+  delUser,
+  changeAssignUser,
+  addUser,
+  updateUser,
+  exportUser,
+  resetUserPwd,
+  changeUserStatus,
+  importTemplate,
+  getUserInit
+} from "@/api/system/sysuser";
+import { getToken } from "@/utils/auth";
+import { treeselect } from "@/api/system/dept";
+import Treeselect from "@riophae/vue-treeselect";
+import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+import load from "@/utils/loading";
+import SaveForm from "@/components/save-form";
 export default {
-  name: 'User',
-  components: { Treeselect },
+  name: "User",
+  components: { Treeselect, SaveForm },
   data() {
     return {
       // 遮罩层
@@ -339,7 +470,7 @@ export default {
       // 用户表格数据
       userList: null,
       // 弹出层标题
-      title: '',
+      title: "",
       // 部门树选项
       deptOptions: undefined,
       // 是否显示弹出层
@@ -355,23 +486,23 @@ export default {
       // 表单参数
       form: {},
       defaultProps: {
-        children: 'children',
-        label: 'deptName'
+        children: "children",
+        label: "deptName"
       },
       // 用户导入参数
       upload: {
         // 是否显示弹出层(用户导入)
         open: false,
         // 弹出层标题(用户导入)
-        title: '',
+        title: "",
         // 是否禁用上传
         isUploading: false,
         // 是否更新已经存在的用户数据
         updateSupport: 0,
         // 设置上传的请求头部
-        headers: { Authorization: 'Bearer ' + getToken() },
+        headers: { Authorization: "Bearer " + getToken() },
         // 上传的地址
-        url: process.env.VUE_APP_BASE_API + '/system/user/importData'
+        url: process.env.VUE_APP_BASE_API + "/system/user/importData"
       },
       // 查询参数
       queryParams: {
@@ -385,31 +516,31 @@ export default {
       // 表单校验
       rules: {
         username: [
-          { required: true, message: '用户名称不能为空', trigger: 'blur' }
+          { required: true, message: "用户名称不能为空", trigger: "blur" }
         ],
         nickName: [
-          { required: true, message: '用户昵称不能为空', trigger: 'blur' }
+          { required: true, message: "用户昵称不能为空", trigger: "blur" }
         ],
         deptIds: [
-          { required: true, message: '归属部门不能为空', trigger: 'blur' }
+          { required: true, message: "归属部门不能为空", trigger: "blur" }
         ],
         password: [
-          { required: true, message: '用户密码不能为空', trigger: 'blur' }
+          { required: true, message: "用户密码不能为空", trigger: "blur" }
         ],
         email: [
-          { required: true, message: '邮箱地址不能为空', trigger: 'blur' },
+          { required: true, message: "邮箱地址不能为空", trigger: "blur" },
           {
-            type: 'email',
+            type: "email",
             message: "'请输入正确的邮箱地址",
-            trigger: ['blur', 'change']
+            trigger: ["blur", "change"]
           }
         ],
         phone: [
-          { required: true, message: '手机号码不能为空', trigger: 'blur' },
+          { required: true, message: "手机号码不能为空", trigger: "blur" },
           {
             pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
-            message: '请输入正确的手机号码',
-            trigger: 'blur'
+            message: "请输入正确的手机号码",
+            trigger: "blur"
           }
         ]
       },
@@ -420,87 +551,95 @@ export default {
       },
       quitRules: {
         toUserId: [
-          { required: true, message: '请选择离职交接人', trigger: 'change' }
+          { required: true, message: "请选择离职交接人", trigger: "change" }
         ]
       },
       users: []
-    }
+    };
   },
   watch: {
     // 根据名称筛选部门树
     deptName(val) {
-      this.$refs.tree.filter(val)
+      this.$refs.tree.filter(val);
     }
   },
-  created() {
-    this.getList()
-    this.getTreeselect()
+  mounted() {
+    this.getList();
+    this.getTreeselect();
   },
   methods: {
     /** 查询用户列表 */
     getList() {
-      this.loading = true
-      listUser(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
-        this.userList = response.data.list
-        this.total = response.data.count
-        this.loading = false
-      }
-      )
+      this.loading = true;
+      listUser(this.addDateRange(this.queryParams, this.dateRange)).then(
+        response => {
+          this.userList = response.data.list;
+          this.total = response.data.count;
+          this.loading = false;
+        }
+      );
     },
     /** 查询部门下拉树结构 */
     getTreeselect() {
       treeselect().then(response => {
-        this.deptOptions = response.data
-      })
+        this.deptOptions = response.data;
+      });
     },
     // 筛选节点
     filterNode(value, data) {
-      if (!value) return true
-      return data.deptName.indexOf(value) !== -1
+      if (!value) return true;
+      return data.deptName.indexOf(value) !== -1;
     },
     // 节点单击事件
     handleNodeClick(data) {
-      this.queryParams.deptId = data.deptId
-      this.getList()
+      this.queryParams.deptId = data.deptId;
+      this.getList();
     },
     /** 转换菜单数据结构 */
     normalizer(node) {
       if (node.children && !node.children.length) {
-        delete node.children
+        delete node.children;
       }
       return {
         id: node.deptId,
         label: node.deptName,
         children: node.children
-      }
+      };
     },
     // 用户状态修改
     handleStatusChange(row) {
-      const text = row.status === '0' ? '启用' : '停用'
-      this.$confirm('确认要"' + text + '""' + row.username + '"用户吗?', '警告', {
-        confirmButtonText: '确定',
-        cancelButtonText: '取消',
-        type: 'warning'
-      }).then(function() {
-        return changeUserStatus(row.userId, row.status)
-      }).then(() => {
-        this.msgSuccess(text + '成功')
-      }).catch(function() {
-        row.status = row.status === '0' ? '1' : '0'
-      })
+      const text = row.status === "0" ? "启用" : "停用";
+      this.$confirm(
+        '确认要"' + text + '""' + row.username + '"用户吗?',
+        "警告",
+        {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }
+      )
+        .then(function() {
+          return changeUserStatus(row.userId, row.status);
+        })
+        .then(() => {
+          this.msgSuccess(text + "成功");
+        })
+        .catch(function() {
+          row.status = row.status === "0" ? "1" : "0";
+        });
     },
     // 取消按钮
     cancel() {
-      this.open = false
-      this.reset()
+      this.open = false;
+      this.reset();
     },
     // 取消按钮
     quitCancel() {
-      this.quitOpen = false
+      this.quitOpen = false;
       this.quitForm = {
         fromUserId: null,
         toUserId: null
-      }
+      };
     },
     // 表单重置
     reset() {
@@ -513,189 +652,209 @@ export default {
         phone: undefined,
         email: undefined,
         sex: undefined,
-        status: '0',
+        status: "0",
         remark: undefined,
         postIds: undefined,
         roleIds: undefined
-      }
-      this.resetForm('form')
+      };
+      this.resetForm("form");
     },
     /** 搜索按钮操作 */
     handleQuery() {
-      this.queryParams.page = 1
-      this.getList()
+      this.queryParams.page = 1;
+      this.getList();
     },
     /** 重置按钮操作 */
     resetQuery() {
-      this.dateRange = []
-      this.resetForm('queryForm')
-      this.handleQuery()
+      this.queryParams = {
+        pageIndex: 1,
+        pageSize: 10,
+        username: undefined,
+        phone: undefined,
+        status: undefined,
+        deptId: undefined
+      };
+      this.dateRange = [];
+      this.resetForm("queryForm");
+      this.handleQuery();
     },
     // 多选框选中数据
     handleSelectionChange(selection) {
-      this.ids = selection.map(item => item.userId)
-      this.single = selection.length !== 1
-      this.multiple = !selection.length
+      this.ids = selection.map(item => item.userId);
+      this.single = selection.length !== 1;
+      this.multiple = !selection.length;
     },
     /** 新增按钮操作 */
     handleAdd() {
-      this.reset()
-      this.getTreeselect()
+      this.reset();
+      this.getTreeselect();
       getUserInit().then(response => {
-        this.postOptions = response.data.posts
-        this.roleOptions = response.data.roles
-        this.open = true
-        this.title = '添加用户'
-        this.form.password = '123456'
-      })
+        this.postOptions = response.data.posts;
+        this.roleOptions = response.data.roles;
+        this.open = true;
+        this.title = "添加用户";
+        this.form.password = "123456";
+      });
     },
     /** 修改按钮操作 */
     handleUpdate(row) {
-      this.reset()
-      this.getTreeselect()
+      this.reset();
+      this.getTreeselect();
 
-      const userId = row.userId || this.ids
+      const userId = row.userId || this.ids;
       getUser(userId).then(response => {
-        this.form = response.data
-        this.postOptions = response.posts
-        this.roleOptions = response.roles
-        this.form.postIds = response.data.postIds
-        this.form.roleIds = response.roleIds[0]
-        this.form.deptId = response.data.deptId || null
-        this.open = true
-        this.title = '修改用户'
-        this.form.password = ''
-      })
+        this.form = response.data;
+        this.postOptions = response.posts;
+        this.roleOptions = response.roles;
+        this.form.postIds = response.data.postIds;
+        this.form.roleIds = response.roleIds[0];
+        this.form.deptId = response.data.deptId || null;
+        this.open = true;
+        this.title = "修改用户";
+        this.form.password = "";
+      });
     },
     /** 离职交接人按钮操作 */
     async handleQuit(row) {
-      load.startLoading()
+      load.startLoading();
       await listUser({
         pageSize: 999999
       }).then(response => {
-        this.users = response.data.list
-      })
-      load.endLoading()
-      this.quitOpen = true
-      this.quitForm.fromUserId = row.userId
+        this.users = response.data.list;
+      });
+      load.endLoading();
+      this.quitOpen = true;
+      this.quitForm.fromUserId = row.userId;
     },
     /** 离职交接操作 */
     submitQuitForm() {
-      this.$refs['quitForm'].validate(valid => {
+      this.$refs["quitForm"].validate(valid => {
         if (valid) {
           changeAssignUser(this.quitForm).then(response => {
             if (response.code === 200) {
-              this.msgSuccess('交接成功')
-              this.quitOpen = false
-              this.getList()
+              this.msgSuccess("交接成功");
+              this.quitOpen = false;
+              this.getList();
             } else {
-              this.msgError(response.msg)
+              this.msgError(response.msg);
             }
-          })
+          });
         }
-      })
+      });
     },
     /** 重置密码按钮操作 */
     handleResetPwd(row) {
-      this.$prompt('请输入"' + row.username + '"的新密码', '提示', {
-        confirmButtonText: '确定',
-        cancelButtonText: '取消'
-      }).then(({ value }) => {
-        if (!value) {
-          this.msgError('重置密码不能为空')
-          return
-        }
-        resetUserPwd(row.userId, value).then(response => {
-          if (response.code === 200) {
-            this.msgSuccess('修改成功,新密码是:' + value)
-          } else {
-            this.msgError(response.msg)
+      this.$prompt('请输入"' + row.username + '"的新密码', "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消"
+      })
+        .then(({ value }) => {
+          if (!value) {
+            this.msgError("重置密码不能为空");
+            return;
           }
+          resetUserPwd(row.userId, value).then(response => {
+            if (response.code === 200) {
+              this.msgSuccess("修改成功,新密码是:" + value);
+            } else {
+              this.msgError(response.msg);
+            }
+          });
         })
-      }).catch(() => {})
+        .catch(() => {});
     },
     /** 提交按钮 */
     submitForm: function() {
-      this.$refs['form'].validate(valid => {
+      this.$refs["form"].validate(valid => {
         if (valid) {
           if (this.form.userId !== undefined) {
             updateUser(this.form).then(response => {
               if (response.code === 200) {
-                this.msgSuccess('修改成功')
-                this.open = false
-                this.getList()
+                this.msgSuccess("修改成功");
+                this.open = false;
+                this.getList();
               } else {
-                this.msgError(response.msg)
+                this.msgError(response.msg);
               }
-            })
+            });
           } else {
             addUser(this.form).then(response => {
               if (response.code === 200) {
-                this.msgSuccess('新增成功')
-                this.open = false
-                this.getList()
+                this.msgSuccess("新增成功");
+                this.open = false;
+                this.getList();
               } else {
-                this.msgError(response.msg)
+                this.msgError(response.msg);
               }
-            })
+            });
           }
         }
-      })
+      });
     },
     /** 删除按钮操作 */
     handleDelete(row) {
-      const userIds = row.userId || this.ids
-      this.$confirm('是否确认删除用户编号为"' + userIds + '"的数据项?', '警告', {
-        confirmButtonText: '确定',
-        cancelButtonText: '取消',
-        type: 'warning'
-      }).then(function() {
-        return delUser(userIds)
-      }).then(() => {
-        this.getList()
-        this.msgSuccess('删除成功')
-      }).catch(function() {})
+      const userIds = row.userId || this.ids;
+      this.$confirm(
+        '是否确认删除用户编号为"' + userIds + '"的数据项?',
+        "警告",
+        {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }
+      )
+        .then(function() {
+          return delUser(userIds);
+        })
+        .then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        })
+        .catch(function() {});
     },
     /** 导出按钮操作 */
     handleExport() {
-      const queryParams = this.queryParams
-      this.$confirm('是否确认导出所有用户数据项?', '警告', {
-        confirmButtonText: '确定',
-        cancelButtonText: '取消',
-        type: 'warning'
-      }).then(function() {
-        return exportUser(queryParams)
-      }).then(response => {
-        this.download(response.msg)
-      }).catch(function() {})
+      const queryParams = this.queryParams;
+      this.$confirm("是否确认导出所有用户数据项?", "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      })
+        .then(function() {
+          return exportUser(queryParams);
+        })
+        .then(response => {
+          this.download(response.msg);
+        })
+        .catch(function() {});
     },
     /** 导入按钮操作 */
     handleImport() {
-      this.upload.title = '用户导入'
-      this.upload.open = true
+      this.upload.title = "用户导入";
+      this.upload.open = true;
     },
     /** 下载模板操作 */
     importTemplate() {
       importTemplate().then(response => {
-        this.download(response.msg)
-      })
+        this.download(response.msg);
+      });
     },
     // 文件上传中处理
     handleFileUploadProgress(event, file, fileList) {
-      this.upload.isUploading = true
+      this.upload.isUploading = true;
     },
     // 文件上传成功处理
     handleFileSuccess(response, file, fileList) {
-      this.upload.open = false
-      this.upload.isUploading = false
-      this.$refs.upload.clearFiles()
-      this.$alert(response.msg, '导入结果', { dangerouslyUseHTMLString: true })
-      this.getList()
+      this.upload.open = false;
+      this.upload.isUploading = false;
+      this.$refs.upload.clearFiles();
+      this.$alert(response.msg, "导入结果", { dangerouslyUseHTMLString: true });
+      this.getList();
     },
     // 提交上传文件
     submitFileForm() {
-      this.$refs.upload.submit()
+      this.$refs.upload.submit();
     }
   }
-}
+};
 </script>