caojunjie 3 years ago
parent
commit
aa6bb88005
45 changed files with 3322 additions and 70 deletions
  1. 1 1
      index.html
  2. 69 2
      package-lock.json
  3. 3 1
      package.json
  4. BIN
      src/assets/banner/BANNER1.png
  5. BIN
      src/assets/banner/BANNER3.png
  6. BIN
      src/assets/banner/BANNER4.png
  7. BIN
      src/assets/banner/BANNER5.png
  8. BIN
      src/assets/banner/BANNER_Z1.jpg
  9. BIN
      src/assets/banner/BANNER_Z2.jpg
  10. BIN
      src/assets/banner/BANNER_Z3.jpg
  11. BIN
      src/assets/banner/BANNER_Z4.jpg
  12. BIN
      src/assets/banner/BANNER_Z5.jpg
  13. BIN
      src/assets/logo.png
  14. BIN
      src/assets/logo2.png
  15. BIN
      src/assets/xinwen.png
  16. BIN
      src/assets/xuanchuan.png
  17. 92 0
      src/components/Breadcrumb/index.vue
  18. 195 0
      src/components/Editor/index.vue
  19. 179 0
      src/components/FileUpload/index.vue
  20. 44 0
      src/components/Hamburger/index.vue
  21. 189 0
      src/components/HeaderSearch/index.vue
  22. 68 0
      src/components/IconSelect/index.vue
  23. 11 0
      src/components/IconSelect/requireIcons.js
  24. 101 0
      src/components/Pagination/index.vue
  25. 142 0
      src/components/PanThumb/index.vue
  26. 3 0
      src/components/ParentView/index.vue
  27. 149 0
      src/components/RightPanel/index.vue
  28. 38 0
      src/components/RightToolbar/index.vue
  29. 21 0
      src/components/RuoYi/Doc/index.vue
  30. 21 0
      src/components/RuoYi/Git/index.vue
  31. 60 0
      src/components/Screenfull/index.vue
  32. 57 0
      src/components/SizeSelect/index.vue
  33. 61 0
      src/components/SvgIcon/index.vue
  34. 175 0
      src/components/ThemePicker/index.vue
  35. 68 0
      src/components/UploadImage/index.vue
  36. 93 0
      src/components/Uploadfile/index.vue
  37. 163 0
      src/components/plugs/print.js
  38. 14 0
      src/main.js
  39. 4 2
      src/request/request.js
  40. 17 0
      src/router/index.js
  41. 73 0
      src/views/aboutUs/introduction.vue
  42. 47 24
      src/views/home/index.vue
  43. 3 3
      src/views/login/index.vue
  44. 31 37
      src/views/navigation/navigation.vue
  45. 1130 0
      src/views/stock/index.vue

+ 1 - 1
index.html

@@ -3,7 +3,7 @@
   <head>
     <meta charset="utf-8">
     <meta name="viewport" content="width=device-width,initial-scale=1.0">
-    <title>凯和船运</title>
+    <title>青岛中电国际物流有限公司</title>
   </head>
   <body style="margin: 0;padding: 0;">
     <div id="app"></div>

+ 69 - 2
package-lock.json

@@ -80,6 +80,21 @@
         "js-tokens": "^3.0.0"
       }
     },
+    "@babel/runtime": {
+      "version": "7.15.3",
+      "resolved": "https://registry.nlark.com/@babel/runtime/download/@babel/runtime-7.15.3.tgz",
+      "integrity": "sha1-LhwogMoRjlsvmYgyK9inZWoyUCs=",
+      "requires": {
+        "regenerator-runtime": "^0.13.4"
+      },
+      "dependencies": {
+        "regenerator-runtime": {
+          "version": "0.13.9",
+          "resolved": "https://registry.nlark.com/regenerator-runtime/download/regenerator-runtime-0.13.9.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fregenerator-runtime%2Fdownload%2Fregenerator-runtime-0.13.9.tgz",
+          "integrity": "sha1-iSV0Kpj/2QgUmI11Zq0wyjsmO1I="
+        }
+      }
+    },
     "@babel/template": {
       "version": "7.0.0-beta.44",
       "resolved": "https://registry.npm.taobao.org/@babel/template/download/@babel/template-7.0.0-beta.44.tgz",
@@ -166,6 +181,21 @@
         }
       }
     },
+    "@riophae/vue-treeselect": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npm.taobao.org/@riophae/vue-treeselect/download/@riophae/vue-treeselect-0.4.0.tgz",
+      "integrity": "sha1-C67Vp5TP/FgLY1kfNcEl5RwN8kE=",
+      "requires": {
+        "@babel/runtime": "^7.3.1",
+        "babel-helper-vue-jsx-merge-props": "^2.0.3",
+        "easings-css": "^1.0.0",
+        "fuzzysearch": "^1.0.3",
+        "is-promise": "^2.1.0",
+        "lodash": "^4.0.0",
+        "material-colors": "^1.2.6",
+        "watch-size": "^2.0.0"
+      }
+    },
     "@sinonjs/commons": {
       "version": "1.8.2",
       "resolved": "https://registry.npm.taobao.org/@sinonjs/commons/download/@sinonjs/commons-1.8.2.tgz?cache=0&sync_timestamp=1610537233421&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40sinonjs%2Fcommons%2Fdownload%2F%40sinonjs%2Fcommons-1.8.2.tgz",
@@ -4294,6 +4324,11 @@
         "stream-shift": "^1.0.0"
       }
     },
+    "easings-css": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npm.taobao.org/easings-css/download/easings-css-1.0.0.tgz",
+      "integrity": "sha1-3eVpADu3pKDAt3h49ds+C+VnnIE="
+    },
     "ecc-jsbn": {
       "version": "0.1.2",
       "resolved": "https://registry.npm.taobao.org/ecc-jsbn/download/ecc-jsbn-0.1.2.tgz",
@@ -5811,6 +5846,11 @@
       "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=",
       "dev": true
     },
+    "fuzzysearch": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npm.taobao.org/fuzzysearch/download/fuzzysearch-1.0.3.tgz",
+      "integrity": "sha1-3/yA9tawQiPyImqnndGUIxCW0Ag="
+    },
     "gauge": {
       "version": "2.7.4",
       "resolved": "https://registry.npm.taobao.org/gauge/download/gauge-2.7.4.tgz",
@@ -7323,6 +7363,11 @@
       "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=",
       "dev": true
     },
+    "is-promise": {
+      "version": "2.2.2",
+      "resolved": "https://registry.npm.taobao.org/is-promise/download/is-promise-2.2.2.tgz",
+      "integrity": "sha1-OauVnMv5p3TPB597QMeib3YxNfE="
+    },
     "is-regex": {
       "version": "1.1.2",
       "resolved": "https://registry.npm.taobao.org/is-regex/download/is-regex-1.1.2.tgz?cache=0&sync_timestamp=1612217453411&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-regex%2Fdownload%2Fis-regex-1.1.2.tgz",
@@ -8013,8 +8058,7 @@
     "lodash": {
       "version": "4.17.21",
       "resolved": "https://registry.npm.taobao.org/lodash/download/lodash-4.17.21.tgz",
-      "integrity": "sha1-Z5WRxWTDv/quhFTPCz3zcMPWkRw=",
-      "dev": true
+      "integrity": "sha1-Z5WRxWTDv/quhFTPCz3zcMPWkRw="
     },
     "lodash._arraycopy": {
       "version": "3.0.0",
@@ -8362,6 +8406,11 @@
         "object-visit": "^1.0.0"
       }
     },
+    "material-colors": {
+      "version": "1.2.6",
+      "resolved": "https://registry.npm.taobao.org/material-colors/download/material-colors-1.2.6.tgz",
+      "integrity": "sha1-bRlYhxEmmSzuzHL0vMTY8BCGX0Y="
+    },
     "math-expression-evaluator": {
       "version": "1.3.7",
       "resolved": "https://registry.npm.taobao.org/math-expression-evaluator/download/math-expression-evaluator-1.3.7.tgz",
@@ -14145,6 +14194,11 @@
         "is-plain-obj": "^1.0.0"
       }
     },
+    "sortablejs": {
+      "version": "1.10.2",
+      "resolved": "https://registry.nlark.com/sortablejs/download/sortablejs-1.10.2.tgz",
+      "integrity": "sha1-bkA2TZE/mLhaFPZnj5K1wSIfUpA="
+    },
     "source-list-map": {
       "version": "2.0.1",
       "resolved": "https://registry.npm.taobao.org/source-list-map/download/source-list-map-2.0.1.tgz",
@@ -15490,6 +15544,19 @@
       "integrity": "sha1-HuO8mhbsv1EYvjNLsV+cRvgvWCU=",
       "dev": true
     },
+    "vuedraggable": {
+      "version": "2.24.3",
+      "resolved": "https://registry.nlark.com/vuedraggable/download/vuedraggable-2.24.3.tgz?cache=0&sync_timestamp=1623379001749&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fvuedraggable%2Fdownload%2Fvuedraggable-2.24.3.tgz",
+      "integrity": "sha1-Q8k4SbdGokzlA+Ej1bJZxwG6DRk=",
+      "requires": {
+        "sortablejs": "1.10.2"
+      }
+    },
+    "watch-size": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npm.taobao.org/watch-size/download/watch-size-2.0.0.tgz",
+      "integrity": "sha1-CW7ijQNlvX6gPZyL8fL1CnO+FHQ="
+    },
     "watchpack": {
       "version": "1.7.5",
       "resolved": "https://registry.npm.taobao.org/watchpack/download/watchpack-1.7.5.tgz",

+ 3 - 1
package.json

@@ -14,12 +14,14 @@
     "build": "node build/build.js"
   },
   "dependencies": {
+    "@riophae/vue-treeselect": "^0.4.0",
     "axios": "^0.21.1",
     "element-ui": "^2.15.1",
     "js-cookie": "^2.2.1",
     "jsencrypt": "^3.2.0",
     "vue": "^2.5.2",
-    "vue-router": "^3.0.1"
+    "vue-router": "^3.0.1",
+    "vuedraggable": "^2.24.3"
   },
   "devDependencies": {
     "autoprefixer": "^7.1.2",

BIN
src/assets/banner/BANNER1.png


BIN
src/assets/banner/BANNER3.png


BIN
src/assets/banner/BANNER4.png


BIN
src/assets/banner/BANNER5.png


BIN
src/assets/banner/BANNER_Z1.jpg


BIN
src/assets/banner/BANNER_Z2.jpg


BIN
src/assets/banner/BANNER_Z3.jpg


BIN
src/assets/banner/BANNER_Z4.jpg


BIN
src/assets/banner/BANNER_Z5.jpg


BIN
src/assets/logo.png


BIN
src/assets/logo2.png


BIN
src/assets/xinwen.png


BIN
src/assets/xuanchuan.png


+ 92 - 0
src/components/Breadcrumb/index.vue

@@ -0,0 +1,92 @@
+<template>
+  <el-breadcrumb class="app-breadcrumb" separator="/">
+    <transition-group name="breadcrumb">
+      <el-breadcrumb-item v-for="(item, index) in levelList" :key="item.path">
+        <span
+          v-if="item.redirect === 'noRedirect' || index == levelList.length - 1"
+          class="no-redirect"
+          >{{ item.meta.title }}</span
+        >
+        <a v-else @click.prevent="handleLink(item)">{{ item.meta.title }}</a>
+      </el-breadcrumb-item>
+    </transition-group>
+  </el-breadcrumb>
+</template>
+
+<script>
+import pathToRegexp from "path-to-regexp";
+
+export default {
+  data() {
+    return {
+      levelList: null,
+    };
+  },
+  watch: {
+    $route(route) {
+      // if you go to the redirect page, do not update the breadcrumbs
+      if (route.path.startsWith("/redirect/")) {
+        return;
+      }
+      this.getBreadcrumb();
+    },
+  },
+  created() {
+    this.getBreadcrumb();
+  },
+  methods: {
+    getBreadcrumb() {
+      // only show routes with meta.title
+      let matched = this.$route.matched.filter(
+        (item) => item.meta && item.meta.title
+      );
+      const first = matched[0];
+
+      if (!this.isDashboard(first)) {
+        matched = [{ path: "/index", meta: { title: "首页" } }].concat(matched);
+      }
+
+      this.levelList = matched.filter(
+        (item) => item.meta && item.meta.title && item.meta.breadcrumb !== false
+      );
+    },
+    isDashboard(route) {
+      const name = route && route.name;
+      if (!name) {
+        return false;
+      }
+      return name.trim() === "首页";
+    },
+    pathCompile(path) {
+      const { params } = this.$route;
+      var toPath = pathToRegexp.compile(path);
+      return toPath(params);
+    },
+    handleLink(item) {
+      const { redirect, path } = item;
+      if (redirect) {
+        this.$router.push(redirect);
+        return;
+      }
+      this.$router.push(this.pathCompile(path));
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.app-breadcrumb.el-breadcrumb {
+  display: inline-block;
+  font-size: 14px;
+  line-height: 50px;
+  margin-left: 8px;
+  .el-breadcrumb__inner.is-link,
+  .el-breadcrumb__inner a {
+    color: #fff;
+  }
+  .no-redirect {
+    color: #fff;
+    cursor: text;
+  }
+}
+</style>

+ 195 - 0
src/components/Editor/index.vue

@@ -0,0 +1,195 @@
+<template>
+    <div class="editor" ref="editor" :style="styles"></div>
+</template>
+
+<script>
+import Quill from "quill";
+import "quill/dist/quill.core.css";
+import "quill/dist/quill.snow.css";
+import "quill/dist/quill.bubble.css";
+
+export default {
+  name: "Editor",
+  props: {
+    /* 编辑器的内容 */
+    value: {
+      type: String,
+      default: "",
+    },
+    /* 高度 */
+    height: {
+      type: Number,
+      default: null,
+    },
+    /* 最小高度 */
+    minHeight: {
+      type: Number,
+      default: null,
+    },
+  },
+  data() {
+    return {
+      Quill: null,
+      currentValue: "",
+      options: {
+        theme: "snow",
+        bounds: document.body,
+        debug: "warn",
+        modules: {
+          // 工具栏配置
+          toolbar: [
+            ["bold", "italic", "underline", "strike"],       // 加粗 斜体 下划线 删除线
+            ["blockquote", "code-block"],                    // 引用  代码块
+            [{ list: "ordered" }, { list: "bullet" }],       // 有序、无序列表
+            [{ indent: "-1" }, { indent: "+1" }],            // 缩进
+            [{ size: ["small", false, "large", "huge"] }],   // 字体大小
+            [{ header: [1, 2, 3, 4, 5, 6, false] }],         // 标题
+            [{ color: [] }, { background: [] }],             // 字体颜色、字体背景颜色
+            [{ align: [] }],                                 // 对齐方式
+            ["clean"],                                       // 清除文本格式
+            ["link", "image", "video"]                       // 链接、图片、视频
+          ],
+        },
+        placeholder: "请输入内容",
+        readOnly: false,
+      },
+    };
+  },
+  computed: {
+    styles() {
+      let style = {};
+      if (this.minHeight) {
+        style.minHeight = `${this.minHeight}px`;
+      }
+      if (this.height) {
+        style.height = `${this.height}px`;
+      }
+      return style;
+    },
+  },
+  watch: {
+    value: {
+      handler(val) {
+        if (val !== this.currentValue) {
+          this.currentValue = val === null ? "" : val;
+          if (this.Quill) {
+            this.Quill.pasteHTML(this.currentValue);
+          }
+        }
+      },
+      immediate: true,
+    },
+  },
+  mounted() {
+    this.init();
+  },
+  beforeDestroy() {
+    this.Quill = null;
+  },
+  methods: {
+    init() {
+      const editor = this.$refs.editor;
+      this.Quill = new Quill(editor, this.options);
+      this.Quill.pasteHTML(this.currentValue);
+      this.Quill.on("text-change", (delta, oldDelta, source) => {
+        const html = this.$refs.editor.children[0].innerHTML;
+        const text = this.Quill.getText();
+        const quill = this.Quill;
+        this.currentValue = html;
+        this.$emit("input", html);
+        this.$emit("on-change", { html, text, quill });
+      });
+      this.Quill.on("text-change", (delta, oldDelta, source) => {
+        this.$emit("on-text-change", delta, oldDelta, source);
+      });
+      this.Quill.on("selection-change", (range, oldRange, source) => {
+        this.$emit("on-selection-change", range, oldRange, source);
+      });
+      this.Quill.on("editor-change", (eventName, ...args) => {
+        this.$emit("on-editor-change", eventName, ...args);
+      });
+    },
+  },
+};
+</script>
+
+<style>
+.editor, .ql-toolbar {
+  white-space: pre-wrap!important;
+  line-height: normal !important;
+}
+.quill-img {
+  display: none;
+}
+.ql-snow .ql-tooltip[data-mode="link"]::before {
+  content: "请输入链接地址:";
+}
+.ql-snow .ql-tooltip.ql-editing a.ql-action::after {
+  border-right: 0px;
+  content: "保存";
+  padding-right: 0px;
+}
+
+.ql-snow .ql-tooltip[data-mode="video"]::before {
+  content: "请输入视频地址:";
+}
+
+.ql-snow .ql-picker.ql-size .ql-picker-label::before,
+.ql-snow .ql-picker.ql-size .ql-picker-item::before {
+  content: "14px";
+}
+.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="small"]::before,
+.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="small"]::before {
+  content: "10px";
+}
+.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="large"]::before,
+.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="large"]::before {
+  content: "18px";
+}
+.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="huge"]::before,
+.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="huge"]::before {
+  content: "32px";
+}
+
+.ql-snow .ql-picker.ql-header .ql-picker-label::before,
+.ql-snow .ql-picker.ql-header .ql-picker-item::before {
+  content: "文本";
+}
+.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before,
+.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before {
+  content: "标题1";
+}
+.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before,
+.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before {
+  content: "标题2";
+}
+.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before,
+.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before {
+  content: "标题3";
+}
+.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before,
+.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before {
+  content: "标题4";
+}
+.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before,
+.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before {
+  content: "标题5";
+}
+.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before,
+.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {
+  content: "标题6";
+}
+
+.ql-snow .ql-picker.ql-font .ql-picker-label::before,
+.ql-snow .ql-picker.ql-font .ql-picker-item::before {
+  content: "标准字体";
+}
+.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="serif"]::before,
+.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="serif"]::before {
+  content: "衬线字体";
+}
+.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="monospace"]::before,
+.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="monospace"]::before {
+  content: "等宽字体";
+}
+</style>

+ 179 - 0
src/components/FileUpload/index.vue

@@ -0,0 +1,179 @@
+<template>
+  <div class="upload-file">
+    <el-upload
+      :action="uploadFileUrl"
+      :before-upload="handleBeforeUpload"
+      :file-list="fileList"
+      :limit="1"
+      :on-error="handleUploadError"
+      :on-exceed="handleExceed"
+      :on-success="handleUploadSuccess"
+      :show-file-list="false"
+      :headers="headers"
+      class="upload-file-uploader"
+      ref="upload"
+    >
+      <!-- 上传按钮 -->
+      <el-button size="mini" type="primary">选取文件</el-button>
+      <!-- 上传提示 -->
+      <div class="el-upload__tip" slot="tip" v-if="showTip">
+        请上传
+        <template v-if="fileSize"> 大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b> </template>
+        <template v-if="fileType"> 格式为 <b style="color: #f56c6c">{{ fileType.join("/") }}</b> </template>
+        的文件
+      </div>
+    </el-upload>
+
+    <!-- 文件列表 -->
+    <transition-group class="upload-file-list el-upload-list el-upload-list--text" name="el-fade-in-linear" tag="ul">
+      <li :key="file.uid" class="el-upload-list__item ele-upload-list__item-content" v-for="(file, index) in list">
+        <el-link :href="file.url" :underline="false" target="_blank">
+          <span class="el-icon-document"> {{ getFileName(file.name) }} </span>
+        </el-link>
+        <div class="ele-upload-list__item-content-action">
+          <el-link :underline="false" @click="handleDelete(index)" type="danger">删除</el-link>
+        </div>
+      </li>
+    </transition-group>
+  </div>
+</template>
+
+<script>
+import { getToken } from "@/utils/auth";
+
+export default {
+  props: {
+    // 值
+    value: [String, Object, Array],
+    // 大小限制(MB)
+    fileSize: {
+      type: Number,
+      default: 5,
+    },
+    // 文件类型, 例如['png', 'jpg', 'jpeg']
+    fileType: {
+      type: Array,
+      default: () => ["doc", "xls", "ppt", "txt", "pdf"],
+    },
+    // 是否显示提示
+    isShowTip: {
+      type: Boolean,
+      default: true
+    }
+  },
+  data() {
+    return {
+      uploadFileUrl: process.env.VUE_APP_BASE_API + "/common/upload", // 上传的图片服务器地址
+      headers: {
+        Authorization: "Bearer " + getToken(),
+      },
+      fileList: [],
+    };
+  },
+  computed: {
+    // 是否显示提示
+    showTip() {
+      return this.isShowTip && (this.fileType || this.fileSize);
+    },
+    // 列表
+    list() {
+      let temp = 1;
+      if (this.value) {
+        // 首先将值转为数组
+        const list = Array.isArray(this.value) ? this.value : [this.value];
+        // 然后将数组转为对象数组
+        return list.map((item) => {
+          if (typeof item === "string") {
+            item = { name: item, url: item };
+          }
+          item.uid = item.uid || new Date().getTime() + temp++;
+          return item;
+        });
+      } else {
+        this.fileList = [];
+        return [];
+      }
+    },
+  },
+  methods: {
+    // 上传前校检格式和大小
+    handleBeforeUpload(file) {
+      // 校检文件类型
+      if (this.fileType) {
+        let fileExtension = "";
+        if (file.name.lastIndexOf(".") > -1) {
+          fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1);
+        }
+        const isTypeOk = this.fileType.some((type) => {
+          if (file.type.indexOf(type) > -1) return true;
+          if (fileExtension && fileExtension.indexOf(type) > -1) return true;
+          return false;
+        });
+        if (!isTypeOk) {
+          this.$message.error(`文件格式不正确, 请上传${this.fileType.join("/")}格式文件!`);
+          return false;
+        }
+      }
+      // 校检文件大小
+      if (this.fileSize) {
+        const isLt = file.size / 1024 / 1024 < this.fileSize;
+        if (!isLt) {
+          this.$message.error(`上传文件大小不能超过 ${this.fileSize} MB!`);
+          return false;
+        }
+      }
+      return true;
+    },
+    // 文件个数超出
+    handleExceed() {
+      this.$message.error(`只允许上传单个文件`);
+    },
+    // 上传失败
+    handleUploadError(err) {
+      this.$message.error("上传失败, 请重试");
+    },
+    // 上传成功回调
+    handleUploadSuccess(res, file) {
+      this.$message.success("上传成功");
+      this.$emit("input", res.url);
+    },
+    // 删除文件
+    handleDelete(index) {
+      this.fileList.splice(index, 1);
+      this.$emit("input", '');
+    },
+    // 获取文件名称
+    getFileName(name) {
+      if (name.lastIndexOf("/") > -1) {
+        return name.slice(name.lastIndexOf("/") + 1).toLowerCase();
+      } else {
+        return "";
+      }
+    }
+  },
+  created() {
+    this.fileList = this.list;
+  },
+};
+</script>
+
+<style scoped lang="scss">
+.upload-file-uploader {
+  margin-bottom: 5px;
+}
+.upload-file-list .el-upload-list__item {
+  border: 1px solid #e4e7ed;
+  line-height: 2;
+  margin-bottom: 10px;
+  position: relative;
+}
+.upload-file-list .ele-upload-list__item-content {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  color: inherit;
+}
+.ele-upload-list__item-content-action .el-link {
+  margin-right: 10px;
+}
+</style>

+ 44 - 0
src/components/Hamburger/index.vue

@@ -0,0 +1,44 @@
+<template>
+  <div style="padding: 0 15px;" @click="toggleClick">
+    <svg
+      :class="{'is-active':isActive}"
+      class="hamburger"
+      viewBox="0 0 1024 1024"
+      xmlns="http://www.w3.org/2000/svg"
+      width="64"
+      height="64"
+    >
+      <path d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z"  fill="#FFFFFF"/>
+    </svg>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'Hamburger',
+  props: {
+    isActive: {
+      type: Boolean,
+      default: false
+    }
+  },
+  methods: {
+    toggleClick() {
+      this.$emit('toggleClick')
+    }
+  }
+}
+</script>
+
+<style scoped>
+.hamburger {
+  display: inline-block;
+  vertical-align: middle;
+  width: 20px;
+  height: 20px;
+}
+
+.hamburger.is-active {
+  transform: rotate(180deg);
+}
+</style>

+ 189 - 0
src/components/HeaderSearch/index.vue

@@ -0,0 +1,189 @@
+<template>
+  <div :class="{'show':show}" class="header-search">
+    <svg-icon class-name="search-icon" icon-class="search" @click.stop="click" />
+    <el-select
+      ref="headerSearchSelect"
+      v-model="search"
+      :remote-method="querySearch"
+      filterable
+      default-first-option
+      remote
+      placeholder="Search"
+      class="header-search-select"
+      @change="change"
+    >
+      <el-option v-for="item in options" :key="item.path" :value="item" :label="item.title.join(' > ')" />
+    </el-select>
+  </div>
+</template>
+
+<script>
+// fuse is a lightweight fuzzy-search module
+// make search results more in line with expectations
+import Fuse from 'fuse.js'
+import path from 'path'
+
+export default {
+  name: 'HeaderSearch',
+  data() {
+    return {
+      search: '',
+      options: [],
+      searchPool: [],
+      show: false,
+      fuse: undefined
+    }
+  },
+  computed: {
+    routes() {
+      return this.$store.getters.permission_routes
+    }
+  },
+  watch: {
+    routes() {
+      this.searchPool = this.generateRoutes(this.routes)
+    },
+    searchPool(list) {
+      this.initFuse(list)
+    },
+    show(value) {
+      if (value) {
+        document.body.addEventListener('click', this.close)
+      } else {
+        document.body.removeEventListener('click', this.close)
+      }
+    }
+  },
+  mounted() {
+    this.searchPool = this.generateRoutes(this.routes)
+  },
+  methods: {
+    click() {
+      this.show = !this.show
+      if (this.show) {
+        this.$refs.headerSearchSelect && this.$refs.headerSearchSelect.focus()
+      }
+    },
+    close() {
+      this.$refs.headerSearchSelect && this.$refs.headerSearchSelect.blur()
+      this.options = []
+      this.show = false
+    },
+    change(val) {
+      if(this.ishttp(val.path)) {
+        // http(s):// 路径新窗口打开
+        window.open(val.path, "_blank");
+      } else {
+        this.$router.push(val.path)
+      }
+      this.search = ''
+      this.options = []
+      this.$nextTick(() => {
+        this.show = false
+      })
+    },
+    initFuse(list) {
+      this.fuse = new Fuse(list, {
+        shouldSort: true,
+        threshold: 0.4,
+        location: 0,
+        distance: 100,
+        maxPatternLength: 32,
+        minMatchCharLength: 1,
+        keys: [{
+          name: 'title',
+          weight: 0.7
+        }, {
+          name: 'path',
+          weight: 0.3
+        }]
+      })
+    },
+    // Filter out the routes that can be displayed in the sidebar
+    // And generate the internationalized title
+    generateRoutes(routes, basePath = '/', prefixTitle = []) {
+      let res = []
+
+      for (const router of routes) {
+        // skip hidden router
+        if (router.hidden) { continue }
+
+        const data = {
+          path: !this.ishttp(router.path) ? path.resolve(basePath, router.path) : router.path,
+          title: [...prefixTitle]
+        }
+
+        if (router.meta && router.meta.title) {
+          data.title = [...data.title, router.meta.title]
+
+          if (router.redirect !== 'noRedirect') {
+            // only push the routes with title
+            // special case: need to exclude parent router without redirect
+            res.push(data)
+          }
+        }
+
+        // recursive child routes
+        if (router.children) {
+          const tempRoutes = this.generateRoutes(router.children, data.path, data.title)
+          if (tempRoutes.length >= 1) {
+            res = [...res, ...tempRoutes]
+          }
+        }
+      }
+      return res
+    },
+    querySearch(query) {
+      if (query !== '') {
+        this.options = this.fuse.search(query)
+      } else {
+        this.options = []
+      }
+    },
+    ishttp(url) {
+      return url.indexOf('http://') !== -1 || url.indexOf('https://') !== -1
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.header-search {
+  font-size: 0 !important;
+
+  .search-icon {
+    cursor: pointer;
+    font-size: 18px;
+    vertical-align: middle;
+    color: #fff;
+  }
+
+  .header-search-select {
+    font-size: 18px;
+    transition: width 0.2s;
+    width: 0;
+    overflow: hidden;
+    background: transparent;
+    border-radius: 0;
+    display: inline-block;
+    vertical-align: middle;
+
+    /deep/ .el-input__inner {
+      border-radius: 0;
+      border: 0;
+      padding-left: 0;
+      padding-right: 0;
+      box-shadow: none !important;
+      border-bottom: 1px solid #d9d9d9;
+      vertical-align: middle;
+    }
+  }
+
+  &.show {
+    .header-search-select {
+      width: 210px;
+      margin-left: 10px;
+    }
+  }
+}
+</style>

+ 68 - 0
src/components/IconSelect/index.vue

@@ -0,0 +1,68 @@
+<!-- @author zhengjie -->
+<template>
+  <div class="icon-body">
+    <el-input v-model="name" style="position: relative;" clearable placeholder="请输入图标名称" @clear="filterIcons" @input.native="filterIcons">
+      <i slot="suffix" class="el-icon-search el-input__icon" />
+    </el-input>
+    <div class="icon-list">
+      <div v-for="(item, index) in iconList" :key="index" @click="selectedIcon(item)">
+        <svg-icon :icon-class="item" style="height: 30px;width: 16px;" />
+        <span>{{ item }}</span>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import icons from './requireIcons'
+export default {
+  name: 'IconSelect',
+  data() {
+    return {
+      name: '',
+      iconList: icons
+    }
+  },
+  methods: {
+    filterIcons() {
+      this.iconList = icons
+      if (this.name) {
+        this.iconList = this.iconList.filter(item => item.includes(this.name))
+      }
+    },
+    selectedIcon(name) {
+      this.$emit('selected', name)
+      document.body.click()
+    },
+    reset() {
+      this.name = ''
+      this.iconList = icons
+    }
+  }
+}
+</script>
+
+<style rel="stylesheet/scss" lang="scss" scoped>
+  .icon-body {
+    width: 100%;
+    padding: 10px;
+    .icon-list {
+      height: 200px;
+      overflow-y: scroll;
+      div {
+        height: 30px;
+        line-height: 30px;
+        margin-bottom: -5px;
+        cursor: pointer;
+        width: 33%;
+        float: left;
+      }
+      span {
+        display: inline-block;
+        vertical-align: -0.15em;
+        fill: currentColor;
+        overflow: hidden;
+      }
+    }
+  }
+</style>

+ 11 - 0
src/components/IconSelect/requireIcons.js

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

+ 101 - 0
src/components/Pagination/index.vue

@@ -0,0 +1,101 @@
+<template>
+  <div :class="{'hidden':hidden}" class="pagination-container">
+    <el-pagination
+      :background="background"
+      :current-page.sync="currentPage"
+      :page-size.sync="pageSize"
+      :layout="layout"
+      :page-sizes="pageSizes"
+      :total="total"
+      v-bind="$attrs"
+      @size-change="handleSizeChange"
+      @current-change="handleCurrentChange"
+    />
+  </div>
+</template>
+
+<script>
+import { scrollTo } from '@/utils/scroll-to'
+
+export default {
+  name: 'Pagination',
+  props: {
+    total: {
+      required: true,
+      type: Number
+    },
+    page: {
+      type: Number,
+      default: 1
+    },
+    limit: {
+      type: Number,
+      default: 20
+    },
+    pageSizes: {
+      type: Array,
+      default() {
+        return [10, 100, 200, 500, 1000]
+      }
+    },
+    layout: {
+      type: String,
+      default: 'total, sizes, prev, pager, next, jumper'
+    },
+    background: {
+      type: Boolean,
+      default: true
+    },
+    autoScroll: {
+      type: Boolean,
+      default: true
+    },
+    hidden: {
+      type: Boolean,
+      default: false
+    }
+  },
+  computed: {
+    currentPage: {
+      get() {
+        return this.page
+      },
+      set(val) {
+        this.$emit('update:page', val)
+      }
+    },
+    pageSize: {
+      get() {
+        return this.limit
+      },
+      set(val) {
+        this.$emit('update:limit', val)
+      }
+    }
+  },
+  methods: {
+    handleSizeChange(val) {
+      this.$emit('pagination', { page: this.currentPage, limit: val })
+      if (this.autoScroll) {
+        scrollTo(0, 800)
+      }
+    },
+    handleCurrentChange(val) {
+      this.$emit('pagination', { page: val, limit: this.pageSize })
+      if (this.autoScroll) {
+        scrollTo(0, 800)
+      }
+    }
+  }
+}
+</script>
+
+<style scoped>
+.pagination-container {
+  background: #fff;
+  padding: 32px 16px;
+}
+.pagination-container.hidden {
+  display: none;
+}
+</style>

+ 142 - 0
src/components/PanThumb/index.vue

@@ -0,0 +1,142 @@
+<template>
+  <div :style="{zIndex:zIndex,height:height,width:width}" class="pan-item">
+    <div class="pan-info">
+      <div class="pan-info-roles-container">
+        <slot />
+      </div>
+    </div>
+    <!-- eslint-disable-next-line -->
+    <div :style="{backgroundImage: `url(${image})`}" class="pan-thumb"></div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'PanThumb',
+  props: {
+    image: {
+      type: String,
+      required: true
+    },
+    zIndex: {
+      type: Number,
+      default: 1
+    },
+    width: {
+      type: String,
+      default: '150px'
+    },
+    height: {
+      type: String,
+      default: '150px'
+    }
+  }
+}
+</script>
+
+<style scoped>
+.pan-item {
+  width: 200px;
+  height: 200px;
+  border-radius: 50%;
+  display: inline-block;
+  position: relative;
+  cursor: default;
+  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
+}
+
+.pan-info-roles-container {
+  padding: 20px;
+  text-align: center;
+}
+
+.pan-thumb {
+  width: 100%;
+  height: 100%;
+  background-position: center center;
+  background-size: cover;
+  border-radius: 50%;
+  overflow: hidden;
+  position: absolute;
+  transform-origin: 95% 40%;
+  transition: all 0.3s ease-in-out;
+}
+
+/* .pan-thumb:after {
+  content: '';
+  width: 8px;
+  height: 8px;
+  position: absolute;
+  border-radius: 50%;
+  top: 40%;
+  left: 95%;
+  margin: -4px 0 0 -4px;
+  background: radial-gradient(ellipse at center, rgba(14, 14, 14, 1) 0%, rgba(125, 126, 125, 1) 100%);
+  box-shadow: 0 0 1px rgba(255, 255, 255, 0.9);
+} */
+
+.pan-info {
+  position: absolute;
+  width: inherit;
+  height: inherit;
+  border-radius: 50%;
+  overflow: hidden;
+  box-shadow: inset 0 0 0 5px rgba(0, 0, 0, 0.05);
+}
+
+.pan-info h3 {
+  color: #fff;
+  text-transform: uppercase;
+  position: relative;
+  letter-spacing: 2px;
+  font-size: 18px;
+  margin: 0 60px;
+  padding: 22px 0 0 0;
+  height: 85px;
+  font-family: 'Open Sans', Arial, sans-serif;
+  text-shadow: 0 0 1px #fff, 0 1px 2px rgba(0, 0, 0, 0.3);
+}
+
+.pan-info p {
+  color: #fff;
+  padding: 10px 5px;
+  font-style: italic;
+  margin: 0 30px;
+  font-size: 12px;
+  border-top: 1px solid rgba(255, 255, 255, 0.5);
+}
+
+.pan-info p a {
+  display: block;
+  color: #333;
+  width: 80px;
+  height: 80px;
+  background: rgba(255, 255, 255, 0.3);
+  border-radius: 50%;
+  color: #fff;
+  font-style: normal;
+  font-weight: 700;
+  text-transform: uppercase;
+  font-size: 9px;
+  letter-spacing: 1px;
+  padding-top: 24px;
+  margin: 7px auto 0;
+  font-family: 'Open Sans', Arial, sans-serif;
+  opacity: 0;
+  transition: transform 0.3s ease-in-out 0.2s, opacity 0.3s ease-in-out 0.2s, background 0.2s linear 0s;
+  transform: translateX(60px) rotate(90deg);
+}
+
+.pan-info p a:hover {
+  background: rgba(255, 255, 255, 0.5);
+}
+
+.pan-item:hover .pan-thumb {
+  transform: rotate(-110deg);
+}
+
+.pan-item:hover .pan-info p a {
+  opacity: 1;
+  transform: translateX(0px) rotate(0deg);
+}
+</style>

+ 3 - 0
src/components/ParentView/index.vue

@@ -0,0 +1,3 @@
+<template >
+  <router-view />
+</template>

+ 149 - 0
src/components/RightPanel/index.vue

@@ -0,0 +1,149 @@
+<template>
+  <div ref="rightPanel" :class="{show:show}" class="rightPanel-container">
+    <div class="rightPanel-background" />
+    <div class="rightPanel">
+      <div class="rightPanel-items">
+        <slot />
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { addClass, removeClass } from '@/utils'
+
+export default {
+  name: 'RightPanel',
+  props: {
+    clickNotClose: {
+      default: false,
+      type: Boolean
+    },
+    buttonTop: {
+      default: 250,
+      type: Number
+    }
+  },
+  computed: {
+    show: {
+      get() {
+        return this.$store.state.settings.showSettings
+      },
+      set(val) {
+        this.$store.dispatch('settings/changeSetting', {
+          key: 'showSettings',
+          value: val
+        })
+      }
+    },
+    theme() {
+      return this.$store.state.settings.theme
+    },
+  },
+  watch: {
+    show(value) {
+      if (value && !this.clickNotClose) {
+        this.addEventClick()
+      }
+      if (value) {
+        addClass(document.body, 'showRightPanel')
+      } else {
+        removeClass(document.body, 'showRightPanel')
+      }
+    }
+  },
+  mounted() {
+    this.insertToBody()
+    this.addEventClick()
+  },
+  beforeDestroy() {
+    const elx = this.$refs.rightPanel
+    elx.remove()
+  },
+  methods: {
+    addEventClick() {
+      window.addEventListener('click', this.closeSidebar)
+    },
+    closeSidebar(evt) {
+      const parent = evt.target.closest('.rightPanel')
+      if (!parent) {
+        this.show = false
+        window.removeEventListener('click', this.closeSidebar)
+      }
+    },
+    insertToBody() {
+      const elx = this.$refs.rightPanel
+      const body = document.querySelector('body')
+      body.insertBefore(elx, body.firstChild)
+    }
+  }
+}
+</script>
+
+<style>
+.showRightPanel {
+  overflow: hidden;
+  position: relative;
+  width: calc(100% - 15px);
+}
+</style>
+
+<style lang="scss" scoped>
+.rightPanel-background {
+  position: fixed;
+  top: 0;
+  left: 0;
+  opacity: 0;
+  transition: opacity .3s cubic-bezier(.7, .3, .1, 1);
+  background: rgba(0, 0, 0, .2);
+  z-index: -1;
+}
+
+.rightPanel {
+  width: 100%;
+  max-width: 260px;
+  height: 100vh;
+  position: fixed;
+  top: 0;
+  right: 0;
+  box-shadow: 0px 0px 15px 0px rgba(0, 0, 0, .05);
+  transition: all .25s cubic-bezier(.7, .3, .1, 1);
+  transform: translate(100%);
+  background: #fff;
+  z-index: 40000;
+}
+
+.show {
+  transition: all .3s cubic-bezier(.7, .3, .1, 1);
+
+  .rightPanel-background {
+    z-index: 20000;
+    opacity: 1;
+    width: 100%;
+    height: 100%;
+  }
+
+  .rightPanel {
+    transform: translate(0);
+  }
+}
+
+.handle-button {
+  width: 48px;
+  height: 48px;
+  position: absolute;
+  left: -48px;
+  text-align: center;
+  font-size: 24px;
+  border-radius: 6px 0 0 6px !important;
+  z-index: 0;
+  pointer-events: auto;
+  cursor: pointer;
+  color: #fff;
+  line-height: 48px;
+  i {
+    font-size: 24px;
+    line-height: 48px;
+  }
+}
+</style>

+ 38 - 0
src/components/RightToolbar/index.vue

@@ -0,0 +1,38 @@
+<!-- @author Shiyn/   huangmx 20200807优化-->
+<template>
+  <div class="top-right-btn">
+    <el-row>
+      <el-tooltip class="item" effect="dark" :content="showSearch ? '隐藏搜索' : '显示搜索'" placement="top">
+        <el-button size="mini" circle icon="el-icon-search" @click="toggleSearch()" />
+      </el-tooltip>
+      <el-tooltip class="item" effect="dark" content="刷新" placement="top">
+        <el-button size="mini" circle icon="el-icon-refresh" @click="refresh()" />
+      </el-tooltip>
+    </el-row>
+  </div>
+</template>
+<script>
+export default {
+  name: "RightToolbar",
+  data() {
+    return {};
+  },
+  props: {
+    showSearch: {
+      type: Boolean,
+      default: true,
+    },
+  },
+
+  methods: {
+    //搜索
+    toggleSearch() {
+      this.$emit("update:showSearch", !this.showSearch);
+    },
+    //刷新
+    refresh() {
+      this.$emit("queryTable");
+    },
+  },
+};
+</script>

+ 21 - 0
src/components/RuoYi/Doc/index.vue

@@ -0,0 +1,21 @@
+<template>
+  <div>
+    <svg-icon icon-class="question" @click="goto"/>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'RuoYiDoc',
+  data() {
+    return {
+      url: 'http://doc.ruoyi.vip/ruoyi-vue'
+    }
+  },
+  methods: {
+    goto() {
+      window.open(this.url)
+    }
+  }
+}
+</script>

+ 21 - 0
src/components/RuoYi/Git/index.vue

@@ -0,0 +1,21 @@
+<template>
+  <div>
+    <svg-icon icon-class="github" @click="goto"/>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'RuoYiGit',
+  data() {
+    return {
+      url: 'https://gitee.com/y_project/RuoYi-Vue'
+    }
+  },
+  methods: {
+    goto() {
+      window.open(this.url)
+    }
+  }
+}
+</script>

+ 60 - 0
src/components/Screenfull/index.vue

@@ -0,0 +1,60 @@
+<template>
+  <div>
+    <svg-icon :icon-class="isFullscreen?'exit-fullscreen':'fullscreen'" @click="click"  style="color:#fff"/>
+  </div>
+</template>
+
+<script>
+import screenfull from 'screenfull'
+
+export default {
+  name: 'Screenfull',
+  data() {
+    return {
+      isFullscreen: false
+    }
+  },
+  mounted() {
+    this.init()
+  },
+  beforeDestroy() {
+    this.destroy()
+  },
+  methods: {
+    click() {
+      if (!screenfull.enabled) {
+        this.$message({
+          message: 'you browser can not work',
+          type: 'warning'
+        })
+        return false
+      }
+      screenfull.toggle()
+    },
+    change() {
+      this.isFullscreen = screenfull.isFullscreen
+    },
+    init() {
+      if (screenfull.enabled) {
+        screenfull.on('change', this.change)
+      }
+    },
+    destroy() {
+      if (screenfull.enabled) {
+        screenfull.off('change', this.change)
+      }
+    }
+  }
+}
+</script>
+
+<style scoped>
+.screenfull-svg {
+  display: inline-block;
+  cursor: pointer;
+  fill: #5a5e66;;
+  width: 20px;
+  height: 20px;
+  vertical-align: 10px;
+}
+</style>

+ 57 - 0
src/components/SizeSelect/index.vue

@@ -0,0 +1,57 @@
+<template>
+  <el-dropdown trigger="click" @command="handleSetSize">
+    <div>
+      <svg-icon class-name="size-icon" icon-class="size" />
+    </div>
+    <el-dropdown-menu slot="dropdown">
+      <el-dropdown-item v-for="item of sizeOptions" :key="item.value" :disabled="size===item.value" :command="item.value">
+        {{
+          item.label }}
+      </el-dropdown-item>
+    </el-dropdown-menu>
+  </el-dropdown>
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      sizeOptions: [
+        { label: 'Default', value: 'default' },
+        { label: 'Medium', value: 'medium' },
+        { label: 'Small', value: 'small' },
+        { label: 'Mini', value: 'mini' }
+      ]
+    }
+  },
+  computed: {
+    size() {
+      return this.$store.getters.size
+    }
+  },
+  methods: {
+    handleSetSize(size) {
+      this.$ELEMENT.size = size
+      this.$store.dispatch('app/setSize', size)
+      this.refreshView()
+      this.$message({
+        message: 'Switch Size Success',
+        type: 'success'
+      })
+    },
+    refreshView() {
+      // In order to make the cached page re-rendered
+      this.$store.dispatch('tagsView/delAllCachedViews', this.$route)
+
+      const { fullPath } = this.$route
+
+      this.$nextTick(() => {
+        this.$router.replace({
+          path: '/redirect' + fullPath
+        })
+      })
+    }
+  }
+
+}
+</script>

+ 61 - 0
src/components/SvgIcon/index.vue

@@ -0,0 +1,61 @@
+<template>
+  <div v-if="isExternal" :style="styleExternalIcon" class="svg-external-icon svg-icon" v-on="$listeners" />
+  <svg v-else :class="svgClass" aria-hidden="true" v-on="$listeners">
+    <use :xlink:href="iconName" />
+  </svg>
+</template>
+
+<script>
+import { isExternal } from '@/utils/validate'
+
+export default {
+  name: 'SvgIcon',
+  props: {
+    iconClass: {
+      type: String,
+      required: true
+    },
+    className: {
+      type: String,
+      default: ''
+    }
+  },
+  computed: {
+    isExternal() {
+      return isExternal(this.iconClass)
+    },
+    iconName() {
+      return `#icon-${this.iconClass}`
+    },
+    svgClass() {
+      if (this.className) {
+        return 'svg-icon ' + this.className
+      } else {
+        return 'svg-icon'
+      }
+    },
+    styleExternalIcon() {
+      return {
+        mask: `url(${this.iconClass}) no-repeat 50% 50%`,
+        '-webkit-mask': `url(${this.iconClass}) no-repeat 50% 50%`
+      }
+    }
+  }
+}
+</script>
+
+<style scoped>
+.svg-icon {
+  width: 1em;
+  height: 1em;
+  vertical-align: -0.15em;
+  fill: currentColor;
+  overflow: hidden;
+}
+
+.svg-external-icon {
+  background-color: currentColor;
+  mask-size: cover!important;
+  display: inline-block;
+}
+</style>

+ 175 - 0
src/components/ThemePicker/index.vue

@@ -0,0 +1,175 @@
+<template>
+  <el-color-picker
+    v-model="theme"
+    :predefine="['#409EFF', '#1890ff', '#304156','#212121','#11a983', '#13c2c2', '#6959CD', '#f5222d', ]"
+    class="theme-picker"
+    popper-class="theme-picker-dropdown"
+  />
+</template>
+
+<script>
+const version = require('element-ui/package.json').version // element-ui version from node_modules
+const ORIGINAL_THEME = '#409EFF' // default color
+
+export default {
+  data() {
+    return {
+      chalk: '', // content of theme-chalk css
+      theme: ''
+    }
+  },
+  computed: {
+    defaultTheme() {
+      return this.$store.state.settings.theme
+    }
+  },
+  watch: {
+    defaultTheme: {
+      handler: function(val, oldVal) {
+        this.theme = val
+      },
+      immediate: true
+    },
+    async theme(val) {
+      const oldVal = this.chalk ? this.theme : ORIGINAL_THEME
+      if (typeof val !== 'string') return
+      const themeCluster = this.getThemeCluster(val.replace('#', ''))
+      const originalCluster = this.getThemeCluster(oldVal.replace('#', ''))
+      console.log(themeCluster, originalCluster)
+
+      const $message = this.$message({
+        message: '  Compiling the theme',
+        customClass: 'theme-message',
+        type: 'success',
+        duration: 0,
+        iconClass: 'el-icon-loading'
+      })
+
+      const getHandler = (variable, id) => {
+        return () => {
+          const originalCluster = this.getThemeCluster(ORIGINAL_THEME.replace('#', ''))
+          const newStyle = this.updateStyle(this[variable], originalCluster, themeCluster)
+
+          let styleTag = document.getElementById(id)
+          if (!styleTag) {
+            styleTag = document.createElement('style')
+            styleTag.setAttribute('id', id)
+            document.head.appendChild(styleTag)
+          }
+          styleTag.innerText = newStyle
+        }
+      }
+
+      if (!this.chalk) {
+        const url = `https://unpkg.com/element-ui@${version}/lib/theme-chalk/index.css`
+        await this.getCSSString(url, 'chalk')
+      }
+
+      const chalkHandler = getHandler('chalk', 'chalk-style')
+
+      chalkHandler()
+
+      const styles = [].slice.call(document.querySelectorAll('style'))
+        .filter(style => {
+          const text = style.innerText
+          return new RegExp(oldVal, 'i').test(text) && !/Chalk Variables/.test(text)
+        })
+      styles.forEach(style => {
+        const { innerText } = style
+        if (typeof innerText !== 'string') return
+        style.innerText = this.updateStyle(innerText, originalCluster, themeCluster)
+      })
+
+      this.$emit('change', val)
+
+      $message.close()
+    }
+  },
+
+  methods: {
+    updateStyle(style, oldCluster, newCluster) {
+      let newStyle = style
+      oldCluster.forEach((color, index) => {
+        newStyle = newStyle.replace(new RegExp(color, 'ig'), newCluster[index])
+      })
+      return newStyle
+    },
+
+    getCSSString(url, variable) {
+      return new Promise(resolve => {
+        const xhr = new XMLHttpRequest()
+        xhr.onreadystatechange = () => {
+          if (xhr.readyState === 4 && xhr.status === 200) {
+            this[variable] = xhr.responseText.replace(/@font-face{[^}]+}/, '')
+            resolve()
+          }
+        }
+        xhr.open('GET', url)
+        xhr.send()
+      })
+    },
+
+    getThemeCluster(theme) {
+      const tintColor = (color, tint) => {
+        let red = parseInt(color.slice(0, 2), 16)
+        let green = parseInt(color.slice(2, 4), 16)
+        let blue = parseInt(color.slice(4, 6), 16)
+
+        if (tint === 0) { // when primary color is in its rgb space
+          return [red, green, blue].join(',')
+        } else {
+          red += Math.round(tint * (255 - red))
+          green += Math.round(tint * (255 - green))
+          blue += Math.round(tint * (255 - blue))
+
+          red = red.toString(16)
+          green = green.toString(16)
+          blue = blue.toString(16)
+
+          return `#${red}${green}${blue}`
+        }
+      }
+
+      const shadeColor = (color, shade) => {
+        let red = parseInt(color.slice(0, 2), 16)
+        let green = parseInt(color.slice(2, 4), 16)
+        let blue = parseInt(color.slice(4, 6), 16)
+
+        red = Math.round((1 - shade) * red)
+        green = Math.round((1 - shade) * green)
+        blue = Math.round((1 - shade) * blue)
+
+        red = red.toString(16)
+        green = green.toString(16)
+        blue = blue.toString(16)
+
+        return `#${red}${green}${blue}`
+      }
+
+      const clusters = [theme]
+      for (let i = 0; i <= 9; i++) {
+        clusters.push(tintColor(theme, Number((i / 10).toFixed(2))))
+      }
+      clusters.push(shadeColor(theme, 0.1))
+      return clusters
+    }
+  }
+}
+</script>
+
+<style>
+.theme-message,
+.theme-picker-dropdown {
+  z-index: 99999 !important;
+}
+
+.theme-picker .el-color-picker__trigger {
+  height: 26px !important;
+  width: 26px !important;
+  padding: 2px;
+}
+
+.theme-picker-dropdown .el-color-dropdown__link-btn {
+  display: none;
+}
+</style>

+ 68 - 0
src/components/UploadImage/index.vue

@@ -0,0 +1,68 @@
+<template>
+  <div class="component-upload-image">
+    <el-upload
+      :action="uploadImgUrl"
+      list-type="picture-card"
+      :on-success="handleUploadSuccess"
+      :before-upload="handleBeforeUpload"
+      :on-error="handleUploadError"
+      name="file"
+      :show-file-list="false"
+      :headers="headers"
+      style="display: inline-block; vertical-align: top"
+    >
+      <img v-if="value" :src="value" class="avatar" />
+      <i v-else class="el-icon-plus avatar-uploader-icon"></i>
+    </el-upload>
+  </div>
+</template>
+
+<script>
+import { getToken } from "@/utils/auth";
+
+export default {
+  components: {},
+  data() {
+    return {
+      uploadImgUrl: process.env.VUE_APP_BASE_API + "/common/upload", // 上传的图片服务器地址
+      headers: {
+        Authorization: "Bearer " + getToken(),
+      },
+    };
+  },
+  props: {
+    value: {
+      type: String,
+      default: "",
+    },
+  },
+  methods: {
+    handleUploadSuccess(res) {
+      this.$emit("input", res.url);
+      this.loading.close();
+    },
+    handleBeforeUpload() {
+      this.loading = this.$loading({
+        lock: true,
+        text: "上传中",
+        background: "rgba(0, 0, 0, 0.7)",
+      });
+    },
+    handleUploadError() {
+      this.$message({
+        type: "error",
+        message: "上传失败",
+      });
+      this.loading.close();
+    },
+  },
+  watch: {},
+};
+</script>
+
+<style scoped lang="scss">
+.avatar {
+  width: 100%;
+  height: 100%;
+}
+</style>

+ 93 - 0
src/components/Uploadfile/index.vue

@@ -0,0 +1,93 @@
+<template>
+  <div style="display: flex; justify-content:center;">
+    <button style="height: 20px"><a target="_blank"  :href=File>查看</a></button>
+    <el-upload
+      class="upload-demo"
+      :action="uploadImgUrl"
+      list-type="picture-card"
+      :on-success="handleUploadSuccess"
+      :before-upload="handleBeforeUpload"
+      :on-error="handleUploadError"
+      name="file"
+      :show-file-list="false"
+      :headers="headers"
+    >
+      <!-- <img v-if="value" :src="value" class="avatar" />
+      <i v-else class="el-icon-plus avatar-uploader-icon"></i> -->
+      <button>上传</button>
+    </el-upload>
+    <button @click="Delete" style="height: 20px; margin-left:10px;">删除</button>
+  </div>
+</template>
+
+<script>
+import { getToken } from "@/utils/auth";
+
+export default {
+  components: {},
+  data() {
+    return {
+      File: '',
+      uploadImgUrl: process.env.VUE_APP_BASE_API + "/common/upload", // 上传的图片服务器地址
+      headers: {
+        Authorization: "Bearer " + getToken(),
+      },
+    };
+  },
+  // props: {
+  //   value: {
+  //     type: String,
+  //     default: "",
+  //   },
+  // },
+  methods: {
+    handleUploadSuccess(res) {
+      console.log(res)
+      this.$emit("input", res);
+      this.$emit("fileName", res.fileName);
+      this.File = res.url;
+      console.log(res.url)
+      this.loading.close();
+    },
+    handleBeforeUpload() {
+      this.loading = this.$loading({
+        lock: true,
+        text: "上传中",
+        background: "rgba(0, 0, 0, 0.7)",
+      });
+    },
+    // 删除
+    Delete() {
+     this.File = '';
+     this.$message('已删除')
+    },
+    handleUploadError() {
+      this.$message({
+        type: "error",
+        message: "上传失败",
+      });
+      this.loading.close();
+    },
+  },
+  watch: {},
+};
+</script>
+
+<style scoped lang="scss">
+.avatar {
+  width: 100%;
+  height: 100%;
+}
+
+.upload-demo /deep/ .el-upload--picture-card {
+  height: 18px;
+  width: 45px;
+  line-height: 18px;
+  border: none;
+  margin-left:10px!important;
+}
+.upload-demo {
+  line-height: 30px;
+   margin-left:0px!important;
+}
+</style>

+ 163 - 0
src/components/plugs/print.js

@@ -0,0 +1,163 @@
+// 打印类属性、方法定义
+/* eslint-disable */
+const Print = function (dom, options) {
+  if (!(this instanceof Print)) return new Print(dom, options);
+
+  this.options = this.extend({
+    'noPrint': '.no-print'
+  }, options);
+
+  if ((typeof dom) === "string") {
+    this.dom = document.querySelector(dom);
+  } else {
+    this.isDOM(dom)
+    this.dom = this.isDOM(dom) ? dom : dom.$el;
+  }
+
+  this.init();
+};
+Print.prototype = {
+  init: function () {
+    var content = this.getStyle() + this.getHtml();
+    this.writeIframe(content);
+  },
+  extend: function (obj, obj2) {
+    for (var k in obj2) {
+      obj[k] = obj2[k];
+    }
+    return obj;
+  },
+
+  getStyle: function () {
+    var str = "",
+      styles = document.querySelectorAll('style,link');
+    for (var i = 0; i < styles.length; i++) {
+      str += styles[i].outerHTML;
+    }
+    str += "<style>" + (this.options.noPrint ? this.options.noPrint : '.no-print') + "{display:none;}</style>";
+
+    return str;
+  },
+
+  getHtml: function () {
+    var inputs = document.querySelectorAll('input');
+    var textareas = document.querySelectorAll('textarea');
+    var selects = document.querySelectorAll('select');
+
+    for (var k = 0; k < inputs.length; k++) {
+      if (inputs[k].type == "checkbox" || inputs[k].type == "radio") {
+        if (inputs[k].checked == true) {
+          inputs[k].setAttribute('checked', "checked")
+        } else {
+          inputs[k].removeAttribute('checked')
+        }
+      } else if (inputs[k].type == "text") {
+        inputs[k].setAttribute('value', inputs[k].value)
+      } else {
+        inputs[k].setAttribute('value', inputs[k].value)
+      }
+    }
+
+    for (var k2 = 0; k2 < textareas.length; k2++) {
+      if (textareas[k2].type == 'textarea') {
+        textareas[k2].innerHTML = textareas[k2].value
+      }
+    }
+
+    for (var k3 = 0; k3 < selects.length; k3++) {
+      if (selects[k3].type == 'select-one') {
+        var child = selects[k3].children;
+        for (var i in child) {
+          if (child[i].tagName == 'OPTION') {
+            if (child[i].selected == true) {
+              child[i].setAttribute('selected', "selected")
+            } else {
+              child[i].removeAttribute('selected')
+            }
+          }
+        }
+      }
+    }
+    // 包裹要打印的元素
+    // fix: https://github.com/xyl66/vuePlugs_printjs/issues/36
+    let outerHTML = this.wrapperRefDom(this.dom).outerHTML
+    return outerHTML;
+  },
+  // 向父级元素循环,包裹当前需要打印的元素
+  // 防止根级别开头的 css 选择器不生效
+  wrapperRefDom: function (refDom) {
+    let prevDom = null
+    let currDom = refDom
+    // 判断当前元素是否在 body 中,不在文档中则直接返回该节点
+    if (!this.isInBody(currDom)) return currDom
+
+    while (currDom) {
+      if (prevDom) {
+        let element = currDom.cloneNode(false)
+        element.appendChild(prevDom)
+        prevDom = element
+      } else {
+        prevDom = currDom.cloneNode(true)
+      }
+
+      currDom = currDom.parentElement
+    }
+
+    return prevDom
+  },
+
+  writeIframe: function (content) {
+    var w, doc, iframe = document.createElement('iframe'),
+      f = document.body.appendChild(iframe);
+    iframe.id = "myIframe";
+    //iframe.style = "position:absolute;width:0;height:0;top:-10px;left:-10px;";
+    iframe.setAttribute('style', 'position:absolute;width:0;height:0;top:-10px;left:-10px;');
+    w = f.contentWindow || f.contentDocument;
+    doc = f.contentDocument || f.contentWindow.document;
+    doc.open();
+    doc.write(content);
+    doc.close();
+    var _this = this
+    iframe.onload = function(){
+      _this.toPrint(w);
+      setTimeout(function () {
+        document.body.removeChild(iframe)
+      }, 100)
+    }
+  },
+
+  toPrint: function (frameWindow) {
+    try {
+      setTimeout(function () {
+        frameWindow.focus();
+        try {
+          if (!frameWindow.document.execCommand('print', false, null)) {
+            frameWindow.print();
+          }
+        } catch (e) {
+          frameWindow.print();
+        }
+        frameWindow.close();
+      }, 10);
+    } catch (err) {
+      console.log('err', err);
+    }
+  },
+  // 检查一个元素是否是 body 元素的后代元素且非 body 元素本身
+  isInBody: function (node) {
+    return (node === document.body) ? false : document.body.contains(node);
+  },
+  isDOM: (typeof HTMLElement === 'object') ?
+    function (obj) {
+      return obj instanceof HTMLElement;
+    } :
+    function (obj) {
+      return obj && typeof obj === 'object' && obj.nodeType === 1 && typeof obj.nodeName === 'string';
+    }
+};
+const MyPlugin = {}
+MyPlugin.install = function (Vue, options) {
+  // 4. 添加实例方法
+  Vue.prototype.$print = Print
+}
+export default MyPlugin

+ 14 - 0
src/main.js

@@ -5,8 +5,22 @@ import App from './App';
 import router from './router';
 import ElementUI from 'element-ui';
 import 'element-ui/lib/theme-chalk/index.css';
+import { parseTime, resetForm, addDateRange, selectDictLabel, selectDictLabels, download, handleTree } from "./utils/ruoyi";
 Vue.use(ElementUI);
 Vue.config.productionTip = false;
+Vue.prototype.parseTime = parseTime
+Vue.prototype.resetForm = resetForm
+Vue.prototype.addDateRange = addDateRange
+Vue.prototype.selectDictLabel = selectDictLabel
+Vue.prototype.selectDictLabels = selectDictLabels
+Vue.prototype.download = download
+Vue.prototype.handleTree = handleTree
+import Pagination from "./components/Pagination";
+Vue.component('Pagination', Pagination)
+//自定义表格工具扩展
+import RightToolbar from "./components/RightToolbar"
+Vue.component('RightToolbar', RightToolbar)
+
 /* eslint-disable no-new */
 new Vue({
   el: '#app',

+ 4 - 2
src/request/request.js

@@ -18,15 +18,17 @@ export function request(config) {
   if (process.env.NODE_ENV === 'development') {
     //测试接口
     // baseURL = "http://192.168.1.143:9010"
-    baseURL = 'https://test.ke.tubaosoft.com/prod-api';
+    // baseURL = 'http://test.ke.tubaosoft.com/prod-api';
+    // baseURL = 'https://test.fms.tubaosoft.com/prod-api';
     // baseURL = 'https://bs.khzclogistics.com/prod-api';
+    baseURL = 'https://zd.tubaosoft.com/prod-api';
   }
   // uEnvProd;生产模式,点击发行
   if (process.env.NODE_ENV === 'production') {
     // baseURL = "http://192.168.137.1:9010"
     //正式接口
     // baseURL = 'https://test.ke.tubaosoft.com/prod-api';
-    baseURL = 'https://bs.khzclogistics.com/prod-api';
+    baseURL = 'https://zd.tubaosoft.com/prod-api';
   }
   process.baseURL = baseURL
   let newVar = axios.create({

+ 17 - 0
src/router/index.js

@@ -11,6 +11,7 @@ export default new Router({
       path: '/',
       name: 'home',
       component: () => import('../views/home/index'),
+      // component: '../views/home/index',
       meta: {
         keepAlive: true,
         footer:true
@@ -79,6 +80,22 @@ export default new Router({
         keepAlive: true,
         footer:true
       }
+    },{
+      path: '/introduction',
+      name: 'introduction',
+      component: () => import('../views/aboutUs/introduction'),
+      meta: {
+        keepAlive: true,
+        footer:true
+      }
+    },{
+      path: '/stock',
+      name: 'stock',
+      component: () => import('../views/stock/index'),
+      meta: {
+        keepAlive: true,
+        footer:true
+      }
     }
   ],
 });

+ 73 - 0
src/views/aboutUs/introduction.vue

@@ -0,0 +1,73 @@
+<template>
+  <div>
+<!--    <div style="width: 100px;margin-top: 18px;float: right;color: #909399;font-size: 15px;margin-right: 11%">-->
+<!--      <span @click="item = false">中文</span>&nbsp;&nbsp;|&nbsp;&nbsp;<span @click="item = true">English</span>-->
+<!--    </div>-->
+<!--    <br>-->
+<!--    <div v-if="item" style="text-align: left;width: 80%;margin: 0 auto">-->
+<!--      <h1 style="text-align: center">英文简介</h1>-->
+<!--      <p style="text-indent:30px;">Qingdao China Electric Power International Logistics Co.,Ltd. ,authorized by China Foreign Trade Department registered in China Industrial and Commercial Bureau,is the first-class international freight agency enterprise.</p>-->
+<!--      <p style="text-indent:30px;">◆ International ocean transportation service,including:undertaking ocean transportation order ship,centralized shipping,port hand-over and take-over,container transportation,container transfer and loading and unloading,bulk cargo transportation and storage allocation of various exporting and importing goods. We also undertake ocean transportation insurance,goods management,applying to Customs,applying to inspection,transportation incidental fee settlement,etc. in place of the clients.</p>-->
+<!--      <p style="text-indent:30px;">◆ International air transportation service,including:undertaking air transportation order plane class,centralized carrying,port hand-over and take-over of various exporting and importing goods. We also undertake air transportation insurance,goods management,applying to Customs,applying to inspection,transportation incidental fee settlement,etc.in place of the clients.</p>-->
+<!--      <p style="text-indent:30px;">◆ Full logistics:cargo's storage 、 distribution 、 transportation 、 packing and re-packing.</p>-->
+<!--      <p style="text-indent:30px;">◆ Large-scale equipment transportation:a professional company can supply large-scale equipment transportation,also can offer the one-stop service of “door to door”</p>-->
+<!--    </div>-->
+    <div style="text-align: left;width: 80%;margin: 0 auto">
+      <h1 style="text-align: center">公司简介</h1>
+      <p><b>一、企业简介:</b></p>
+      <p style="text-indent:30px;">青岛中电国际物流有限公司是经国家对外经贸部批准,由国家工商局注册的一级国际货运代理企业。公司注册资金人民币伍佰万元整。</p>
+      <p style="text-indent:30px;">青岛中电国际物流有限公司,是以国际航运为主业,集船运代理、货运代理、公路运输(包括特种车辆运输)、空运、码头、仓储、报关业务为一体,公司拥有多个国内分支机构及合资公司,公司现已成为世界货运联盟(WCA)重要成员,并拥有无船承运人(NVOCC)资质及拥有自己在交通部注册备案的提单,业务遍及世界180多个国家和地区,公司并于2016年初发展成为了阿里巴巴一达通本地服务商!</p>
+      <p style="text-indent:30px;">在传统的国际国内集装箱运输及代理业务基础上,公司现有综合业务包括大型仓储拆箱配送物流、多式联运、大陆桥运输、散杂货物租船代运、项目物流(含新建、改建和扩建纸业、电力等工程项目)、产品物流、过境保税加工、仓储等全方位的物流服务。 青岛中电国际物流有限公司拥有一支精良的项目管理队伍,以基于客户需求的项目营销为中心,致力于为客户提供全方位、一流的物流运输方案和实践,从而实现降低成本,提高利润的物流目标。</p>
+      <p><b>二、公司经营范围:</b></p>
+      <p style="text-indent:100px;">一、国际海洋运输业务</p>
+      <p style="text-indent:100px;">提供各类进出口货物的海运订舱、集中托运、港口交接、集装箱运输、中转及拆拼箱、散货运输、仓储分拨;并可代客户办理海运保险、理货、报关报检、结算运杂费等服务。</p>
+      <p style="text-indent:100px;">二、国际散杂货租船业务</p>
+      <p style="text-indent:100px;">提供各类进出口大宗散货、件杂货的租船订舱、报盘、询价、条款确认、签订各类船舶租船协议;并提供陆路运输、码头卸货、装船等全程“门到门”服务。</p>
+      <p style="text-indent:100px;">三、国际航空运输业务</p>
+      <p style="text-indent:100px;">提供各类进出口货物的空运订舱、集中托运、港口交接;并可代客户办理空运保险、理货、报关报检、结算运杂费等服务。四、国际项目物流业务提供各类进出口货物的海运、汽运(大型设备运输)、铁路、空运组成的全程“门到门”联运服务。</p>
+      <p style="text-indent:100px;">五、国际仓储物流业务</p>
+      <p style="text-indent:100px;">提供各类进出口货物的仓储、分拨、装卸、搬运运输等服务。</p>
+      <p style="text-indent:100px;">六、国内报关报检业务</p>
+      <p style="text-indent:100px;">提供各类进出口货物的清关、报检、查验代理服务。</p>
+      <p><b>代理进出口业务涉及产品:</b></p>
+      <p style="text-indent:100px;">棉花类:</p>
+      <p style="text-indent:100px;">年平均代理进口量达15万吨左右。服务客户:中国储备棉管理总公司、中纺棉花进出口公司、魏桥纺织、青岛纺联控股集团,河南同舟棉业有限公司、上海阳丰、中普伟业国际贸易、江苏开元、宁波工艺进出口CARGILL、百达瑞斯、艾伦堡等。</p>
+      <p style="text-indent:100px;">纸浆类:</p>
+      <p style="text-indent:100px;">年平均代理进口量达15万吨左右。</p>
+      <p style="text-indent:100px;">服务客户:IP(美国国际纸业)、中国纸张纸浆进出口公司、比利时威特隆、亚太森博、太阳纸业、晨鸣纸业等。</p>
+      <p style="text-indent:100px;">化工品类:</p>
+      <p style="text-indent:100px;">年平均代理进口量达8万吨。</p>
+      <p style="text-indent:100px;">服务客户:巴西淡水河谷、三角轮胎、耐克、阿迪、韩国浦项等。</p>
+      <p style="text-indent:100px;">设备类:</p>
+      <p style="text-indent:100px;">年平均代理进口量达9万立方。</p>
+      <p style="text-indent:100px;">服务客户:中石化、中海油、西门子、北海船厂、山东电力设备厂、山东亚太森博、日照钢铁、大宇造船等。</p>
+      <p style="text-indent:100px;">出口业务:</p>
+      <p style="text-indent:100px;">年出口代理量1.2万TEU。</p>
+      <p style="text-indent:100px;">服务客户遍及国内食品、农副产品、光伏产品、电线电缆、精密仪器、橡胶制品等。</p>
+      <p><b>三、仓储平台</b></p>
+      <p><b>四、联系我们:</b></p>
+      <p style="text-indent:100px;">公司名称:青岛中电国际物流有限公司</p>
+      <p style="text-indent:100px;">English:Qingdao China Electric Power International Logistics Co.,Ltd</p>
+      <p style="text-indent:100px;">地址:青岛市香港中路68号华普大厦17A</p>
+      <p style="text-indent:100px;">邮编:266071</p>
+      <p style="text-indent:100px;">电话:86-532-85709113</p>
+      <p style="text-indent:100px;">传真:86-532-85708276</p>
+      <p style="text-indent:100px;">网址:<a href="http://www.ceifaqd.com">www.ceifaqd.com</a></p>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+name: "introduction",
+  data(){
+  return{
+    item:false
+  }
+  }
+}
+</script>
+
+<style scoped>
+
+</style>

+ 47 - 24
src/views/home/index.vue

@@ -1,18 +1,17 @@
 <template>
   <div style="background-color: #f2f6f9">
-    <el-carousel height="700px" indicator-position="none">
-<!--      <el-carousel-item>-->
-<!--        <img style="width: 100%;height: 700px;" src="http://www.kaihegroup.cn/repository/image/jjIOSFJySR6gOwMl_7_lAQ.jpg?k=1606198825000" alt="">-->
-<!--      </el-carousel-item>-->
-      <el-carousel-item>
-        <img style="width: 100%;height: 700px;" src="https://www.dmu.com.cn/images/banner/banner41.jpg?v=2" alt="">
-      </el-carousel-item>
-      <el-carousel-item>
-        <img style="width: 100%;height: 700px;" src="https://www.dmu.com.cn/images/banner/banner1.jpg?v=1" alt="">
+    <el-carousel height="600px" indicator-position="none">
+      <el-carousel-item v-for="(item,index) in backgroundDiv" :key="index">
+        <div
+          class="background"
+          style="width: 100%;height: 600px;"
+          :style="item"
+        >
+        </div>
       </el-carousel-item>
     </el-carousel>
-<!--    浮动块-->
-<!--    <div style="width: 60%;height: 300px;background-color: #e32121;margin: 100px auto"></div>-->
+    <!--    浮动块-->
+    <!--    <div style="width: 60%;height: 300px;background-color: #e32121;margin: 100px auto"></div>-->
     <div style="width: 100%;background-color: #f2f6f9;padding-top: 10px;padding-bottom: 10px">
       <div style="margin-bottom: 30px">
         <h1 style="margin-bottom: -5px">SERVICE</h1>
@@ -35,13 +34,13 @@
         </div>
       </div>
     </div>
-    <div style="width: 100%;height: 600px;background-color: #FFFFFF;padding-top: 10px">
-      <div style="margin-bottom: 30px;">
-        <h1 style="margin-bottom: -5px">SERVICE</h1>
-        <span style="border-bottom: 3px solid #25c4cd">快捷服务</span>
-      </div>
-      <img src="../../assets/xinwen.png" alt="">
-    </div>
+    <!--    <div style="width: 100%;height: 600px;background-color: #FFFFFF;padding-top: 10px">-->
+    <!--      <div style="margin-bottom: 30px;">-->
+    <!--        <h1 style="margin-bottom: -5px">SERVICE</h1>-->
+    <!--        <span style="border-bottom: 3px solid #25c4cd">新闻资讯</span>-->
+    <!--      </div>-->
+    <!--      <img src="../../assets/xinwen.png" alt="">-->
+    <!--    </div>-->
     <div style="width: 100%;background-color: #1e4fba;margin-bottom: -10px">
       <img src="../../assets/xuanchuan.png" alt="" style="width: 100%;">
     </div>
@@ -51,9 +50,20 @@
 <script>
 export default {
   name: 'home',
-  methods:{
-    myOrder(){
-      this.$router.push({path: '/myorder'});
+  data() {
+    return {
+      backgroundDiv: [
+        {background: 'transparent url(' + require('../../assets/banner/BANNER_Z1.jpg') + ') no-repeat 0px -680px'},
+        {background: 'transparent url(' + require('../../assets/banner/BANNER_Z2.jpg') + ') no-repeat 0px -480px'},
+        {background: 'transparent url(' + require('../../assets/banner/BANNER_Z3.jpg') + ') no-repeat 0px -480px'},
+        {background: 'transparent url(' + require('../../assets/banner/BANNER_Z4.jpg') + ') no-repeat 0px -480px'},
+        {background: 'transparent url(' + require('../../assets/banner/BANNER_Z5.jpg') + ') no-repeat 0px -480px'}
+      ]
+    };
+  },
+  methods: {
+    myOrder() {
+      // this.$router.push({path: '/myorder'});
     }
   }
 };
@@ -62,30 +72,38 @@ export default {
 <style scoped lang="scss">
 .el-row {
   margin-bottom: 20px;
-&:last-child {
-   margin-bottom: 0;
- }
+
+  &:last-child {
+    margin-bottom: 0;
+  }
 }
+
 .el-col {
   border-radius: 4px;
 }
+
 .bg-purple-dark {
   background: #99a9bf;
 }
+
 .bg-purple {
   background: #d3dce6;
 }
+
 .bg-purple-light {
   background: #e5e9f2;
 }
+
 .grid-content {
   border-radius: 4px;
   min-height: 36px;
 }
+
 .row-bg {
   padding: 10px 0;
   background-color: #f9fafc;
 }
+
 .el-carousel__item h3 {
   color: #475669;
   font-size: 18px;
@@ -93,6 +111,7 @@ export default {
   line-height: 300px;
   margin: 0;
 }
+
 .el-carousel__item:nth-child(2n) {
   background-color: #99a9bf;
 }
@@ -100,4 +119,8 @@ export default {
 .el-carousel__item:nth-child(2n+1) {
   background-color: #d3dce6;
 }
+
+/deep/ .background {
+  background-size: 100% !important
+}
 </style>

+ 3 - 3
src/views/login/index.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="login">
     <el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form">
-      <h3 class="title">凯和船运平台</h3>
+      <h3 class="title">青岛中电国际物流有限公司</h3>
       <el-form-item prop="username">
         <el-input v-model="loginForm.username" type="text" auto-complete="off" placeholder="账号">
           <!--          <svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" />-->
@@ -65,7 +65,7 @@ export default {
   data() {
     return {
       codeUrl: "",
-      company_name:'凯和船运',
+      company_name:'青岛中电国际物流有限公司',
       cookiePassword: "",
       loginForm: {
         username: "",
@@ -176,7 +176,7 @@ export default {
   height: 100%;
   background-color: #2c3e50;
   position: absolute;
-  background-image: url("../../assets/login-background.jpg");
+  background-image: url("https://www.dmu.com.cn/images/banner/banner41.jpg?v=2");
   background-size: cover;
 }
 .title {

+ 31 - 37
src/views/navigation/navigation.vue

@@ -5,51 +5,38 @@
       class="el-menu-demo"
       mode="horizontal"
       @select="handleSelect">
-      <img src="../../assets/logo.png" alt="" style="float: left;width: 15%;margin-top: 10px">
+      <img src="../../assets/logo.png" alt="" style="float: left;width: 4%;margin-top: 10px">
       <el-menu-item index="/">首页</el-menu-item>
       <el-submenu index="2">
-        <template slot="title">我要下单</template>
-<!--        <el-menu-item index="2-1">合约下单</el-menu-item>-->
-        <el-menu-item index="/inquiryAndOrder">查询下单</el-menu-item>
+        <template slot="title">关于我们</template>
+        <el-menu-item index="/introduction">公司简介</el-menu-item>
+        <el-menu-item index="23">总经理致辞</el-menu-item>
+        <el-menu-item index="12">人力资源</el-menu-item>
+        <el-menu-item index="0">发展资质</el-menu-item>
+        <el-menu-item index="9">荣誉资质</el-menu-item>
+        <el-menu-item index="8">合作伙伴</el-menu-item>
       </el-submenu>
       <el-submenu index="3">
-        <template slot="title">订单管理</template>
-<!--        <el-menu-item index="3-1">订仓须知</el-menu-item>-->
-<!--        <el-menu-item index="3-2">我的模板</el-menu-item>-->
-        <el-menu-item index="/myorder">我的订单</el-menu-item>
-<!--        <el-menu-item index="3-4">申请放货</el-menu-item>-->
-<!--        <el-menu-item index="3-5">拆改单</el-menu-item>-->
-<!--        <el-menu-item index="3-6">在线换单</el-menu-item>-->
+        <template slot="title">新闻资讯</template>
+        <el-menu-item index="7">公司新闻</el-menu-item>
+        <el-menu-item index="6">行业动态</el-menu-item>
+        <el-menu-item index="5">政策法规</el-menu-item>
       </el-submenu>
       <el-submenu index="4">
-        <template slot="title">我要结算</template>
-<!--        <el-menu-item index="4-1">结算说明</el-menu-item>-->
-        <el-menu-item index="/settlementCenter">生成账单</el-menu-item>
-        <el-menu-item index="/confirmTheBill">确认账单</el-menu-item>
-        <el-menu-item index="/applyForInvoice">申请发票</el-menu-item>
+        <template slot="title">服务项目</template>
+        <el-menu-item index="4">营销网络</el-menu-item>
+        <el-menu-item index="3">主营业务</el-menu-item>
+        <el-menu-item index="/stock">配套业务</el-menu-item>
       </el-submenu>
-      <el-submenu index="5">
-        <template slot="title">货物跟踪</template>
-<!--        <el-menu-item index="5-1">货运跟踪</el-menu-item>-->
-<!--        <el-menu-item index="5-2">签收单查询</el-menu-item>-->
-      </el-submenu>
-      <el-submenu index="6">
-        <template slot="title">客服中心</template>
-<!--        <el-menu-item index="6-1">办事处</el-menu-item>-->
-<!--        <el-menu-item index="6-2">客服 : 2880866298</el-menu-item>-->
-<!--        <el-menu-item index="6-2">客服 : 2880866300</el-menu-item>-->
-<!--        <el-menu-item index="6-2">客服 : 2885228653</el-menu-item>-->
-      </el-submenu>
-      <el-submenu index="7">
-        <template slot="title">用户中心</template>
-<!--        <el-menu-item index="7-1">个人信息</el-menu-item>-->
-<!--        <el-menu-item index="7-2">消息中心</el-menu-item>-->
-<!--        <el-menu-item index="7-3">开票信息</el-menu-item>-->
-<!--        <el-menu-item index="7-4">积分会员</el-menu-item>-->
-<!--        <el-menu-item index="7-5">账户余额</el-menu-item>-->
-<!--        <el-menu-item index="7-6">优惠券</el-menu-item>-->
-<!--        <el-menu-item index="7-7">帐号管理</el-menu-item>-->
+      <el-submenu index="52">
+        <template slot="title">联系我们</template>
+        <el-menu-item index="">联系电话:86-532-85709113</el-menu-item>
+<!--        <el-menu-item index="">联系邮箱:00888888@163.com</el-menu-item>-->
+        <el-menu-item index="">公司地址:青岛市香港中路68号华普大厦17A</el-menu-item>
       </el-submenu>
+<!--      <div style="width: 100px;margin-top: 18px;float: right;color: #909399;font-size: 15px;" @click="warning">-->
+<!--        中文&nbsp;&nbsp;|&nbsp;&nbsp;English-->
+<!--      </div>-->
       <div style="width: 100px;margin-top: 18px;float: right;color: #909399;font-size: 15px;" @click="immediately" v-if="loginStatus === false">
         登录
       </div>
@@ -87,6 +74,13 @@ export default {
     }
   },
   methods: {
+    warning(){
+      this.$message({
+        showClose: true,
+        message: '暂无此功能',
+        type: 'warning'
+      });
+    },
     cancellation(){
       Cookies.remove('TokenKey');
       this.loginStatus = false

+ 1130 - 0
src/views/stock/index.vue

@@ -0,0 +1,1130 @@
+<template>
+  <div class="app-container">
+    <el-form
+      :model="queryParams"
+      ref="queryForm"
+      :inline="true"
+      v-show="showSearch"
+      label-width="68px"
+    >
+      <el-form-item label="客户" prop="fCorpid">
+        <el-select
+          v-model="queryParams.fCorpid"
+          filterable
+          remote
+          style="width: 200px"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+          :remote-method="corpsRemoteMethod"
+          placeholder="请选择客户"
+        >
+          <el-option
+            v-for="(dict, index) in fMblnoOptions"
+            :key="index.fId"
+            :label="dict.fName"
+            :value="dict.fId"
+          ></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="提单号" prop="fMblno">
+        <el-input
+          v-model="queryParams.fMblno"
+          placeholder="请输入提单号"
+          clearable
+          style="width: 200px"
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="箱号" prop="fCntrno">
+        <el-input
+          v-model="queryParams.fCntrno"
+          placeholder="请输入箱号"
+          clearable
+          style="width: 200px"
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+<!--      <el-form-item label="入库日期" prop="createTime">-->
+<!--        <el-date-picker-->
+<!--          v-model="queryParams.orgStorageDate"-->
+<!--          type="daterange"-->
+<!--          value-format="yyyy-MM-dd"-->
+<!--          clearable-->
+<!--          size="small"-->
+<!--          style="width: 240px"-->
+<!--          range-separator="至"-->
+<!--          start-placeholder="开始日期"-->
+<!--          end-placeholder="结束日期"-->
+<!--          @keyup.enter.native="handleQuery"-->
+<!--        >-->
+<!--        </el-date-picker>-->
+<!--      </el-form-item>-->
+      <el-form-item label="仓库" prop="fwarehouseid">
+        <treeselect
+          style="width: 200px"
+          v-model="queryParams.fWarehouseLocationid"
+          :options="fWarehouseidOption"
+          @select="treeseLect"
+          :show-count="true"
+          size="small"
+          placeholder="请选择归属库区"
+        />
+      </el-form-item>
+      <el-form-item label="货物名称" prop="fgoodsid">
+        <el-select
+          v-model="queryParams.fGoodsid"
+          filterable
+          remote
+          style="width: 200px"
+          clearable
+          size="small"
+          :remote-method="goodsRemoteMethod"
+          @keyup.enter.native="handleQuery"
+          placeholder="请选择货物名称"
+        >
+          <el-option
+            v-for="(dict, index) in goodsOptions"
+            :key="index.fId"
+            :label="dict.fName"
+            :value="dict.fId"
+          ></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="贸易方式" prop="fTrademodeid">
+        <el-select
+          v-model="queryParams.fTrademodeid"
+          placeholder="请选择贸易方式"
+          clearable
+          style="width: 200px"
+          size="small"
+          @keyup.enter.native="handleQuery"
+        >
+          <el-option
+            v-for="(dict, index) in fTrademodeidOptions"
+            :key="index.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="按照箱号">
+        <el-select
+          v-model="queryParams.isCntrno"
+          filterable
+          remote
+          style="width: 200px"
+          clearable
+          size="small"
+        >
+          <el-option
+            v-for="(dict, index) in isCntrnoOptions"
+            :key="index.id"
+            :label="dict.name"
+            :value="dict.id"
+          ></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="库存箱号" prop="fLocalcntrno">
+        <el-input
+          v-model="queryParams.fLocalcntrno"
+          placeholder="库存箱号"
+          clearable
+          style="width: 200px"
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="属性详情" prop="fMarks">
+        <el-input
+          v-model="queryParams.fMarks"
+          placeholder="属性详情"
+          clearable
+          style="width: 200px"
+          size="small"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button
+          type="cyan"
+          icon="el-icon-search"
+          size="mini"
+          @click="handleQuery"
+        >搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <div class="tabSetting">
+<!--        <el-col :span="1.5">-->
+<!--          <el-button-->
+<!--            type="warning"-->
+<!--            icon="el-icon-download"-->
+<!--            size="mini"-->
+<!--            @click="handleExport"-->
+<!--          >导出</el-button-->
+<!--          >-->
+<!--        </el-col>-->
+        <right-toolbar
+          :showSearch.sync="showSearch"
+          @queryTable="getList"
+        ></right-toolbar>
+        <div style="margin: 0 12px">
+          <el-button
+            icon="el-icon-setting"
+            size="mini"
+            circle
+            @click="showSetting = !showSetting"
+          ></el-button>
+        </div>
+      </div>
+    </el-row>
+    <el-dialog title="自定义列显示" :visible.sync="showSetting" width="700px" append-to-body>
+      <div>配置排序列数据(拖动调整顺序)</div>
+      <div style="margin-left: 17px">
+        <el-checkbox
+          v-model="allCheck"
+          label="全选"
+          @change="allChecked"
+        ></el-checkbox>
+      </div>
+      <div style="padding: 4px; display: flex; justify-content: center">
+        <draggable
+          v-model="setRowList"
+          group="site"
+          animation="300"
+          @start="onStart"
+          @end="onEnd"
+          handle=".indraggable"
+        >
+          <transition-group>
+            <div
+              v-for="item in setRowList"
+              :key="item.surface"
+              class="listStyle"
+            >
+              <div style="width: 500px" class="indraggable">
+                <div class="progress" :style="{ width: item.width + 'px' }">
+                  <el-checkbox
+                    :label="item.name"
+                    v-model="item.checked"
+                    :true-label="0"
+                    :false-label="1"
+                  >{{ item.name }}
+                  </el-checkbox>
+                </div>
+              </div>
+              <el-input-number
+                v-model.number="item.width"
+                controls-position="right"
+                :min="1"
+                :max="500"
+                size="mini"
+              ></el-input-number>
+            </div>
+          </transition-group>
+        </draggable>
+      </div>
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="showSetting = false">取 消</el-button>
+        <el-button @click="delRow" type="danger">重 置</el-button>
+        <el-button type="primary" @click="save()">确 定</el-button>
+      </span>
+    </el-dialog>
+    <el-table
+      v-loading="loading"
+      :data="whgenlegList"
+      show-summary
+      :summary-method="getSum"
+      ref="table"
+      :height="tableHeight"
+    >
+      <el-table-column
+        type="index"
+        label="行号"
+        align="center"
+        width="100"
+        fixed
+      />
+      <el-table-column
+        v-for="(item, index) in getRowList"
+        :key="index"
+        :label="item.name"
+        :width="item.width"
+        :prop="item.label"
+        align="center"
+        :show-overflow-tooltip="true"
+        sortable
+        :fixed="item.fixed"
+      >
+        <template slot-scope="scope">
+          <span v-if="item.label == 'fMblno'">
+            <el-link :underline="false" type="primary"
+            ><div @click="goDetail(scope.row)">
+                {{ scope.row.fMblno }}
+              </div></el-link
+            >
+          </span>
+          <span v-else>{{ scope.row[item.label] }}</span>
+        </template>
+      </el-table-column>
+    </el-table>
+<!--    <el-pagination-->
+<!--      v-show="total > 0"-->
+<!--      :total="total"-->
+<!--      :page.sync="queryParams.pageNum"-->
+<!--      :limit.sync="queryParams.pageSize"-->
+<!--      :page-sizes="[50, 100, 200, 500, 1000]"-->
+<!--      @pagination="getList">-->
+<!--    </el-pagination>-->
+    <pagination
+      v-show="total > 0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      :page-sizes="[50, 100, 200, 500, 1000]"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改库存总账对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="原始入库业务编号" prop="fOriginalbillno">
+          <el-input
+            v-model="form.fOriginalbillno"
+            placeholder="请输入原始入库业务编号"
+          />
+        </el-form-item>
+        <el-form-item label="上期件数" prop="fPreqty">
+          <el-input v-model="form.fPreqty" placeholder="请输入上期件数" />
+        </el-form-item>
+        <el-form-item
+          label="上期毛重,单位为吨,保留6位小数"
+          prop="fPregrossweight"
+        >
+          <el-input
+            v-model="form.fPregrossweight"
+            placeholder="请输入上期毛重,单位为吨,保留6位小数"
+          />
+        </el-form-item>
+        <el-form-item label="上期净重," prop="fPrenetweight">
+          <el-input
+            v-model="form.fPrenetweight"
+            placeholder="请输入上期净重,"
+          />
+        </el-form-item>
+        <el-form-item label="入库件数" prop="fQtyd">
+          <el-input v-model="form.fQtyd" placeholder="请输入入库件数" />
+        </el-form-item>
+        <el-form-item label="入库尺码" prop="fVolumnd">
+          <el-input v-model="form.fVolumnd" placeholder="请输入入库尺码" />
+        </el-form-item>
+        <el-form-item label="入库毛重" prop="fGrossweightd">
+          <el-input v-model="form.fGrossweightd" placeholder="请输入入库毛重" />
+        </el-form-item>
+        <el-form-item label="入库净重" prop="fNetweightd">
+          <el-input v-model="form.fNetweightd" placeholder="请输入入库净重" />
+        </el-form-item>
+        <el-form-item label="出口尺码" prop="fVolumnc">
+          <el-input v-model="form.fVolumnc" placeholder="请输入出口尺码" />
+        </el-form-item>
+        <el-form-item label="出库件数" prop="fQtyc">
+          <el-input v-model="form.fQtyc" placeholder="请输入出库件数" />
+        </el-form-item>
+        <el-form-item label="结余件数" prop="fQtyblc">
+          <el-input v-model="form.fQtyblc" placeholder="请输入结余件数" />
+        </el-form-item>
+        <el-form-item label="出库毛重,单位为吨" prop="fGrossweightc">
+          <el-input
+            v-model="form.fGrossweightc"
+            placeholder="请输入出库毛重,单位为吨"
+          />
+        </el-form-item>
+        <el-form-item label="出库净重" prop="fNetweightc">
+          <el-input v-model="form.fNetweightc" placeholder="请输入出库净重" />
+        </el-form-item>
+        <el-form-item label="结余毛重" prop="fGrossweightblc">
+          <el-input
+            v-model="form.fGrossweightblc"
+            placeholder="请输入结余毛重"
+          />
+        </el-form-item>
+        <el-form-item label="结余净重" prop="fNetweightblc">
+          <el-input v-model="form.fNetweightblc" placeholder="请输入结余净重" />
+        </el-form-item>
+        <el-form-item label="箱号" prop="fCntrno">
+          <el-input v-model="form.fCntrno" placeholder="请输入箱号" />
+        </el-form-item>
+        <el-form-item label="状态,默认 T ,正常T 停用F 下拉选择">
+          <el-radio-group v-model="form.fStatus">
+            <el-radio label="1">请选择字典生成</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="删除状态" prop="delFlag">
+          <el-input v-model="form.delFlag" placeholder="请输入删除状态" />
+        </el-form-item>
+        <el-form-item label="唛头" prop="fMarks">
+          <el-input v-model="form.fMarks" placeholder="请输入唛头" />
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+          <el-input
+            v-model="form.remark"
+            type="textarea"
+            placeholder="请输入内容"
+          />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { request } from '../../request/request';
+
+import Treeselect from "@riophae/vue-treeselect";
+import Cookies from "js-cookie";
+import draggable from "vuedraggable";
+import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+
+export default {
+  name: "Whgenleg",
+  components: {
+    Treeselect,
+    draggable,
+  },
+  data() {
+    return {
+      tableHeight: '0',
+      //仓库树状下拉
+      fWarehouseidOption: [],
+      // 客户(客户数据)
+      fMblnoOptions: [],
+      // 贸易方式(数据字典),对应t_trademodels 字典
+      fTrademodeidOptions: [],
+      // 货物
+      goodsOptions: [],
+      // 仓库(仓库数据)
+      warehouseOptions: [],
+      kqhouseOptions: [],
+      // 遮罩层
+      loading: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 库存总账表格数据
+      whgenlegList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 50,
+        fOriginalbillno: null,
+        isCntrno: 1,
+        fPreqty: null,
+        fLocalcntrno: null,
+        fPregrossweight: null,
+        fPrenetweight: null,
+        fQtyd: null,
+        fVolumnd: null,
+        fGrossweightd: null,
+        fNetweightd: null,
+        fVolumnc: null,
+        fQtyc: null,
+        fQtyblc: null,
+        fGrossweightc: null,
+        fNetweightc: null,
+        fGrossweightblc: null,
+        fNetweightblc: null,
+        fCntrno: null,
+        fStatus: null,
+        fMarks: null,
+        orgStorageDate: null,
+        fBusinessType: null,
+        fBusinessTypes: null,
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        fMarks: [{ required: true, message: "唛头不能为空", trigger: "blur" }],
+      },
+      showSetting: false,
+      drag: false,
+      setRowList: [],
+      getRowList: [],
+      tableDate: [
+        {
+          surface: "0",
+          label: "fMblno",
+          name: "提单号",
+          checked: 0,
+          width: 100,
+          fixed: "left",
+        },
+        {
+          surface: "1",
+          label: "fCorpid",
+          name: "客户",
+          checked: 0,
+          width: 100,
+          fixed: "left",
+        },
+        {
+          surface: "2",
+          label: "fOriginalbilldate",
+          name: "入库日期",
+          checked: 0,
+          width: 100,
+          fixed: "left",
+        },
+        {
+          surface: "3",
+          label: "fChargedate",
+          name: "仓储费日期",
+          checked: 0,
+          width: 100,
+          fixed: "left",
+        },
+        {
+          surface: "4",
+          label: "fBusinessTypes",
+          name: "货物属性",
+          checked: 0,
+          width: 100,
+        },
+        {
+          surface: "5",
+          label: "fMarks",
+          name: "属性详情",
+          checked: 0,
+          width: 100,
+        },
+        {
+          surface: "6",
+          label: "fGoodsids",
+          name: "品名",
+          checked: 0,
+          width: 100,
+        },
+        {
+          surface: "8",
+          label: "fWarehouseids",
+          name: "仓库",
+          checked: 0,
+          width: 100,
+        },
+        {
+          surface: "9",
+          label: "fTrademodeid",
+          name: "贸易方式",
+          checked: 0,
+          width: 100,
+        },
+        {
+          surface: "10",
+          label: "fQtyD",
+          name: "入库件数",
+          checked: 0,
+          width: 100,
+        },
+        {
+          surface: "11",
+          label: "fGrossweightD",
+          name: "入库毛重(kg)",
+          checked: 0,
+          width: 100,
+        },
+        {
+          surface: "12",
+          label: "fNetweightD",
+          name: "入库净重(kg)",
+          checked: 0,
+          width: 100,
+        },
+        {
+          surface: "13",
+          label: "fQtyC",
+          name: "出库件数",
+          checked: 0,
+          width: 100,
+        },
+        {
+          surface: "14",
+          label: "fGrossweightC",
+          name: "出库毛重(kg)",
+          checked: 0,
+          width: 100,
+        },
+        {
+          surface: "15",
+          label: "fNetweightC",
+          name: "出库净重(kg)",
+          checked: 0,
+          width: 100,
+        },
+        {
+          surface: "16",
+          label: "fQtyblc",
+          name: "结余件数",
+          checked: 0,
+          width: 100,
+        },
+        {
+          surface: "17",
+          label: "fGrossweightblc",
+          name: "结余毛重(kg)",
+          checked: 0,
+          width: 100,
+        },
+        {
+          surface: "18",
+          label: "fNetweightblc",
+          name: "结余净重(kg)",
+          checked: 0,
+          width: 100,
+        },
+        {
+          surface: "19",
+          label: "fCntrno",
+          name: "箱号",
+          checked: 0,
+          width: 100,
+        },
+        {
+          surface: "20",
+          label: "remark",
+          name: "备注",
+          checked: 0,
+          width: 100,
+        },
+        {
+          surface: "21",
+          label: "fLocalcntrno",
+          name: "库存箱号",
+          checked: 0,
+          width: 100,
+        },
+      ],
+      allCheck: false,
+      isCntrnoOptions: [
+        {
+          id: 0,
+          name: "是",
+        },
+        {
+          id: 1,
+          name: "否",
+        },
+      ],
+    };
+  },
+  created() {
+    let date = new Date();
+    let year = parseInt(date.getFullYear())
+    let month = parseInt(date.getMonth() + 1)
+    let currentMonth = date.getMonth()
+    let nextMonth = ++currentMonth
+    let nextMonthFirstDay = new Date(date.getFullYear(), nextMonth, 1)  // 下个月的第一天
+    let oneDay = 1000*60*60*24
+    let lastTime = new Date(nextMonthFirstDay - oneDay) // 下个月的第一天减去一天,就是上个月的最后一天
+    let day = lastTime.getDate()
+    if (day < 10) {
+      day = '0' + day
+    }
+    // this.queryParams.orgStorageDate = [year + '-' + month + '-' + '01 00:00:00', year + '-' + month + '-' + day + ' 23:59:59']
+
+    this.setRowList = this.tableDate;
+    this.getRowList = this.tableDate;
+    this.getList();
+    request({
+      url: '/system/dict/data/type/' + 'data_trademodes',
+      method: 'get'
+    }).then((response) => {
+      this.fTrademodeidOptions = response.data;
+    });
+    request({
+      url: '/basicdata/warehouse/treeselect',
+      method: 'get'
+    }).then((response) => {
+      this.fWarehouseidOption = response.data.data;
+    });
+    this.getRow();
+  },
+  mounted() {
+    this.$nextTick(() => {
+      // 根据浏览器高度设置初始高度
+      this.tableHeight = window.innerHeight - this.$refs.table.$el.offsetTop - 160
+      // 监听浏览器高度变化,改变表格高度
+      window.onresize = () => {
+        this.tableHeight = window.innerHeight - this.$refs.table.$el.offsetTop - 70
+      }
+    })
+  },
+  methods: {
+    //列设置全选
+    allChecked() {
+      if (this.allCheck == true) {
+        this.setRowList.map((e) => {
+          return (e.checked = 0);
+        });
+      } else {
+        this.setRowList.map((e) => {
+          return (e.checked = 1);
+        });
+      }
+    },
+    //查询列数据
+    getRow() {
+      let that = this;
+      this.data = {
+        tableName: "库存总账",
+        userId: Cookies.get("userName"),
+      };
+      console.log(Cookies.get("userName"));
+      request({
+        url: '/system/set/select',
+        method: 'get',
+        params: this.data
+      }).then((res) => {
+        if (res.data.length != 0) {
+          this.getRowList = res.data.data.filter((e) => e.checked == 0);
+          this.setRowList = res.data.data;
+          this.setRowList = this.setRowList.reduce((res, item) => {
+            res.push({
+              surface: item.surface,
+              label: item.label,
+              name: item.name,
+              checked: item.checked,
+              width: item.width,
+              fixed: item.fixed,
+            });
+            return res;
+          }, []);
+        }
+        console.log(this.getRowList);
+      });
+    },
+    delRow() {
+      this.data = {
+        tableName: "库存总账",
+        userId: Cookies.get("userName"),
+      };
+      request({
+        url: '/system/set/resetModule',
+        method: 'post',
+        data: this.data
+      }).then((res) => {
+        if (res.data.code == 200) {
+          this.showSetting = false;
+          this.setRowList = this.tableDate;
+          this.getRowList = this.tableDate;
+          // console.log(this.getRowList);
+        }
+      });
+    },
+    //保存列设置
+    save() {
+      this.showSetting = false;
+      this.data = {
+        tableName: "库存总账",
+        userId: Cookies.get("userName"),
+        sysTableSetList: this.setRowList,
+      };
+      request({
+        url: '/system/set',
+        method: 'post',
+        data: this.data
+      }).then((res) => {
+        if (res.data.code == 200) {
+          this.showSetting = false;
+          this.getRowList = this.setRowList.filter((e) => e.checked == 0);
+        }
+      });
+    },
+    //开始拖拽事件
+    onStart() {
+      this.drag = true;
+    },
+    //拖拽结束事件
+    onEnd() {
+      this.drag = false;
+    },
+    //合计
+    getSum(param) {
+      const { columns, data } = param;
+      const sums = [];
+      var values = [];
+      columns.forEach((column, index) => {
+        if (index === 0) {
+          sums[index] = "总计";
+        }
+        if (column.property === "fGrossweightD") {
+          values = data.map((item) => Number(item["fGrossweightD"]));
+        }
+        if (column.property === "fNetweightD") {
+          values = data.map((item) => Number(item["fNetweightD"]));
+        }
+        if (column.property === "fQtyD") {
+          values = data.map((item) => Number(item["fQtyD"]));
+        }
+        if (column.property === "fGrossweightC") {
+          values = data.map((item) => Number(item["fGrossweightC"]));
+        }
+        if (column.property === "fNetweightC") {
+          values = data.map((item) => Number(item["fNetweightC"]));
+        }
+        if (column.property === "fQtyC") {
+          values = data.map((item) => Number(item["fQtyC"]));
+        }
+        if (column.property === "fQtyblc") {
+          values = data.map((item) => Number(item["fQtyblc"]));
+        }
+        if (column.property === "fGrossweightblc") {
+          values = data.map((item) => Number(item["fGrossweightblc"]));
+        }
+        if (column.property === "fNetweightblc") {
+          values = data.map((item) => Number(item["fNetweightblc"]));
+        }
+        if (
+          column.property === "fGrossweightD" ||
+          column.property === "fNetweightD" ||
+          column.property === "fQtyD" ||
+          column.property === "fGrossweightC" ||
+          column.property === "fNetweightC" ||
+          column.property === "fQtyC" ||
+          column.property === "fQtyblc" ||
+          column.property === "fGrossweightblc" ||
+          column.property === "fNetweightblc"
+        ) {
+          const values = data.map((item) => Number(item[column.property]));
+          if (!values.every((value) => isNaN(value))) {
+            sums[index] = values.reduce((prev, curr) => {
+              const value = Number(curr);
+              if (!isNaN(value)) {
+                return prev + curr;
+              } else {
+                return prev;
+              }
+            }, 0);
+            if (column.property === "fGrossweightD") {
+              sums[index] = (sums[index] / 1000).toFixed(2) + "吨";
+            }
+            if (column.property === "fNetweightD") {
+              sums[index] = (sums[index] / 1000).toFixed(2) + "吨";
+            }
+            if (column.property === "fQtyD") {
+              sums[index] = sums[index].toFixed(2);
+            }
+            if (column.property === "fGrossweightC") {
+              sums[index] = (sums[index] / 1000).toFixed(2) + "吨";
+            }
+            if (column.property === "fNetweightC") {
+              sums[index] = (sums[index] / 1000).toFixed(2) + "吨";
+            }
+            if (column.property === "fQtyC") {
+              sums[index] = sums[index].toFixed(2);
+            }
+            if (column.property === "fGrossweightblc") {
+              sums[index] = (sums[index] / 1000).toFixed(2) + "吨";
+            }
+            if (column.property === "fNetweightblc") {
+              sums[index] = (sums[index] / 1000).toFixed(2) + "吨";
+            }
+            if (column.property === "fQtyblc") {
+              sums[index] = sums[index].toFixed(2);
+            }
+          }
+        }
+      });
+      return sums;
+    },
+    treeseLect(tree) {
+      this.queryParams.fWarehouseLocationid = tree.id;
+    },
+    getTreeselect() {
+      request({
+        url: '/basicdata/warehouse/treeselect',
+        method: 'get'
+      }).then((response) => {
+        this.warehousesOptions = response.data.data;
+      });
+    },
+    // 贸易方式(数据字典),对���t_trademodels 字典翻译
+    fTrademodeidFormat(row, column) {
+      return this.selectDictLabel(this.fTrademodeidOptions, row.fTrademodeid);
+    },
+    /* 远程模糊查询仓库 */
+    warehouseRemoteMethod(name) {
+      if (name == null || name === "") {
+        return false;
+      }
+      let queryParams = { pageNum: 1, pageSize: 10, fName: name };
+      request({
+        url: '/basicdata/area/list',
+        method: 'get',
+        params: queryParams
+      }).then((response) => {
+        this.warehouseOptions = response.data.rows;
+      });
+    },
+    /* 远程模糊查询库区 */
+    kqhouseRemoteMethod(name) {
+      if (name == null || name === "") {
+        return false;
+      }
+      if (!this.queryParams.fWarehouseid) {
+        this.$message.error("请输入仓库!");
+        return false;
+      }
+      let queryParams = {
+        pageNum: 1,
+        pageSize: 10,
+        fWarehouseid: this.queryParams.fWarehouseid,
+        fName: name,
+      };
+      request({
+        url: '/basicdata/area/list',
+        method: 'get',
+        params: queryParams
+      }).then((response) => {
+        this.kqhouseOptions = response.data.rows;
+      });
+    },
+    /* 远程模糊查询商品 */
+    goodsRemoteMethod(name) {
+      if (name == null || name === "") {
+        return false;
+      }
+      let queryParams = { pageNum: 1, pageSize: 10, fName: name };
+      request({
+        url: '/basicdata/goods/list',
+        method: 'get',
+        params: queryParams
+      }).then((response) => {
+        this.goodsOptions = response.data.rows;
+      });
+    },
+    /* 远程模糊查询用户 */
+    corpsRemoteMethod(name) {
+      if (name == null || name === "") {
+        return false;
+      }
+      let queryParams = { pageNum: 1, pageSize: 10, fName: name };
+      request({
+        // url: '/basicdata/corps/selectCustomerDriverList',
+        url: '/basicdata/corps/list',
+        method: 'get',
+        params: queryParams
+      }).then((response) => {
+        this.fMblnoOptions = response.rows;
+        this.KHblnoOptions = response.rows;
+      });
+    },
+    /** 查询库存总账列表 */
+    getList() {
+      this.loading = true;
+      request({
+        url: '/warehouseBusiness/whgenleg/whgenlegList',
+        method: 'get',
+        params: this.queryParams
+      }).then((response) => {
+        console.log(response);
+        response.data.rows.map((e) => {
+          e.fCntrno=this.queryParams.isCntrno == 1 ? null:e.fCntrno
+        })
+        this.whgenlegList = response.data.rows;
+        this.total = response.data.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        fAccyear: null,
+        fId: null,
+        fAccmonth: null,
+        fCorpid: null,
+        fMblno: null,
+        fOriginalbillno: null,
+        fWarehouseLocationid: null,
+        fGoodsid: null,
+        fTrademodeid: null,
+        fPreqty: null,
+        fPregrossweight: null,
+        fPrenetweight: null,
+        fQtyd: null,
+        fVolumnd: null,
+        fGrossweightd: null,
+        fNetweightd: null,
+        fVolumnc: null,
+        fQtyc: null,
+        fQtyblc: null,
+        fGrossweightc: null,
+        fNetweightc: null,
+        fGrossweightblc: null,
+        fNetweightblc: null,
+        fCntrno: null,
+        fStatus: "0",
+        delFlag: null,
+        createBy: null,
+        fMarks: null,
+        createTime: null,
+        updateBy: null,
+        updateTime: null,
+        remark: null,
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.queryParams = {
+        pageNum: 1,
+        pageSize: 10,
+        fOriginalbillno: null,
+        fPreqty: null,
+        fPregrossweight: null,
+        fPrenetweight: null,
+        fQtyd: null,
+        fVolumnd: null,
+        fGrossweightd: null,
+        fNetweightd: null,
+        fVolumnc: null,
+        fQtyc: null,
+        fQtyblc: null,
+        fGrossweightc: null,
+        fNetweightc: null,
+        fGrossweightblc: null,
+        fNetweightblc: null,
+        fCntrno: null,
+        fStatus: null,
+        fMarks: null,
+        fBusinessType: null,
+        fBusinessTypes: null,
+        fBilltype: null,
+        fwarehouseid: null,
+      };
+      // this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加库存总账";
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate((valid) => {
+        if (valid) {
+          if (this.form.fAccyear != null) {
+            request({
+              url: '/warehouseBusiness/whgenleg',
+              method: 'put',
+              data: this.form
+            }).then((response) => {
+              this.$message({
+                message: '修改成功',
+                type: 'success'
+              });
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            request({
+              url: '/warehouseBusiness/whgenleg',
+              method: 'post',
+              data: this.form
+            }).then((response) => {
+              this.$message({
+                message: '新增成功',
+                type: 'success'
+              });
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm("是否确认导出所有库存总账数据项?", "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning",
+      }).then(function () {
+          return request({
+            url: '/warehouseBusiness/whgenleg/export',
+            method: 'get',
+            params: queryParams
+          });
+        }).then((response) => {
+        window.location.href("/common/download?fileName=" + response.data.msg + "&delete=" + true);
+        });
+    },
+    goDetail(row) {
+      this.$router.push({
+        path: "/analysis/stockDetail",
+        query: {
+          fWarehouseLocationid: row.fWarehouseLocationid,
+          fTrademodeids: row.fTrademodeids,
+          fBusinessType: row.fBusinessType,
+          fGoodsid: row.fGoodsid,
+          fCorpIds: row.fCorpIds,
+          fMarks: row.fMarks,
+          fMblno: row.fMblno,
+        },
+      });
+    },
+  },
+};
+</script>
+<style lang="scss">
+.el-table {
+  .el-table__body-wrapper {
+    z-index: 2;
+  }
+}
+.tabSetting {
+  display: flex;
+  justify-content: flex-end;
+}
+.listStyle {
+  display: flex;
+  border-top: 1px solid #dcdfe6;
+  border-left: 1px solid #dcdfe6;
+  border-right: 1px solid #dcdfe6;
+}
+.listStyle:last-child {
+  border-bottom: 1px solid #dcdfe6;
+}
+.progress {
+  display: flex;
+  align-items: center;
+  padding: 2px;
+  background-color: rgba(0, 0, 0, 0.05);
+  height: 100%;
+}
+</style>