ソースを参照

feat: #初始化页面

loki 4 年 前
コミット
755ef48192

+ 281 - 274
.eslintrc.js

@@ -9,279 +9,286 @@ module.exports = {
     node: true,
     es6: true
   },
-  extends: ['plugin:vue/recommended', 'eslint:recommended'],
+  parser: 'vue-eslint-parser'
+  // extends: ["plugin:vue/essential"]
 
-  // add your custom rules here
-  //it is base on https://github.com/vuejs/eslint-config-vue
-  rules: {
-    'vue/html-self-closing': [
-      0,
-      {
-        html: {
-          void: 'always',
-          normal: 'never',
-          component: 'always'
-        },
-        svg: 'always',
-        math: 'always'
-      }
-    ],
-    'vue/max-attributes-per-line': [
-      2,
-      {
-        singleline: 10,
-        multiline: {
-          max: 1,
-          allowFirstLine: false
-        }
-      }
-    ],
-    'vue/singleline-html-element-content-newline': 'off',
-    'vue/multiline-html-element-content-newline': 'off',
-    'vue/name-property-casing': ['error', 'PascalCase'],
-    'vue/no-v-html': 'off',
-    'accessor-pairs': 2,
-    'arrow-spacing': [
-      2,
-      {
-        before: true,
-        after: true
-      }
-    ],
-    'block-spacing': [2, 'always'],
-    'brace-style': [
-      2,
-      '1tbs',
-      {
-        allowSingleLine: true
-      }
-    ],
-    camelcase: [
-      0,
-      {
-        properties: 'always'
-      }
-    ],
-    'comma-dangle': [2, 'never'],
-    'comma-spacing': [
-      2,
-      {
-        before: false,
-        after: true
-      }
-    ],
-    'comma-style': [2, 'last'],
-    'constructor-super': 2,
-    curly: [2, 'multi-line'],
-    'dot-location': [2, 'property'],
-    'eol-last': 2,
-    eqeqeq: ['error', 'always', { null: 'ignore' }],
-    'generator-star-spacing': [
-      2,
-      {
-        before: true,
-        after: true
-      }
-    ],
-    'handle-callback-err': [2, '^(err|error)$'],
-    indent: [
-      2,
-      2,
-      {
-        SwitchCase: 1
-      }
-    ],
-    'jsx-quotes': [2, 'prefer-single'],
-    'key-spacing': [
-      2,
-      {
-        beforeColon: false,
-        afterColon: true
-      }
-    ],
-    'keyword-spacing': [
-      2,
-      {
-        before: true,
-        after: true
-      }
-    ],
-    'new-cap': [
-      2,
-      {
-        newIsCap: true,
-        capIsNew: false
-      }
-    ],
-    'new-parens': 2,
-    'no-array-constructor': 2,
-    'no-caller': 2,
-    'no-console': 'off',
-    'no-class-assign': 2,
-    'no-cond-assign': 2,
-    'no-const-assign': 2,
-    'no-control-regex': 0,
-    'no-delete-var': 2,
-    'no-dupe-args': 2,
-    'no-dupe-class-members': 2,
-    'no-dupe-keys': 2,
-    'no-duplicate-case': 2,
-    'no-empty-character-class': 2,
-    'no-empty-pattern': 2,
-    'no-eval': 2,
-    'no-ex-assign': 2,
-    'no-extend-native': 2,
-    'no-extra-bind': 2,
-    'no-extra-boolean-cast': 2,
-    'no-extra-parens': [2, 'functions'],
-    'no-fallthrough': 2,
-    'no-floating-decimal': 2,
-    'no-func-assign': 2,
-    'no-implied-eval': 2,
-    'no-inner-declarations': [2, 'functions'],
-    'no-invalid-regexp': 2,
-    'no-irregular-whitespace': 2,
-    'no-iterator': 2,
-    'no-label-var': 2,
-    'no-labels': [
-      2,
-      {
-        allowLoop: false,
-        allowSwitch: false
-      }
-    ],
-    'no-lone-blocks': 2,
-    'no-mixed-spaces-and-tabs': 2,
-    'no-multi-spaces': 2,
-    'no-multi-str': 2,
-    'no-multiple-empty-lines': [
-      2,
-      {
-        max: 1
-      }
-    ],
-    'no-native-reassign': 2,
-    'no-negated-in-lhs': 2,
-    'no-new-object': 2,
-    'no-new-require': 2,
-    'no-new-symbol': 2,
-    'no-new-wrappers': 2,
-    'no-obj-calls': 2,
-    'no-octal': 2,
-    'no-octal-escape': 2,
-    'no-path-concat': 2,
-    'no-proto': 2,
-    'no-redeclare': 2,
-    'no-regex-spaces': 2,
-    'no-return-assign': [2, 'except-parens'],
-    'no-self-assign': 2,
-    'no-self-compare': 2,
-    'no-sequences': 2,
-    'no-shadow-restricted-names': 2,
-    'no-spaced-func': 2,
-    'no-sparse-arrays': 2,
-    'no-this-before-super': 2,
-    'no-throw-literal': 2,
-    'no-trailing-spaces': 2,
-    'no-undef': 2,
-    'no-undef-init': 2,
-    'no-unexpected-multiline': 2,
-    'no-unmodified-loop-condition': 2,
-    'no-unneeded-ternary': [
-      2,
-      {
-        defaultAssignment: false
-      }
-    ],
-    'no-unreachable': 2,
-    'no-unsafe-finally': 2,
-    'no-unused-vars': [
-      2,
-      {
-        vars: 'all',
-        args: 'none'
-      }
-    ],
-    'no-useless-call': 2,
-    'no-useless-computed-key': 2,
-    'no-useless-constructor': 2,
-    'no-useless-escape': 0,
-    'no-whitespace-before-property': 2,
-    'no-with': 2,
-    'one-var': [
-      2,
-      {
-        initialized: 'never'
-      }
-    ],
-    'operator-linebreak': [
-      2,
-      'after',
-      {
-        overrides: {
-          '?': 'before',
-          ':': 'before'
-        }
-      }
-    ],
-    'padded-blocks': [2, 'never'],
-    quotes: [
-      2,
-      'single',
-      {
-        avoidEscape: true,
-        allowTemplateLiterals: true
-      }
-    ],
-    semi: [0, 'never'],
-    'semi-spacing': [
-      0,
-      {
-        before: false,
-        after: true
-      }
-    ],
-    'space-before-blocks': [2, 'always'],
-    'space-before-function-paren': [2, 'never'],
-    'space-in-parens': [2, 'never'],
-    'space-infix-ops': 2,
-    'space-unary-ops': [
-      2,
-      {
-        words: true,
-        nonwords: false
-      }
-    ],
-    'spaced-comment': [
-      2,
-      'always',
-      {
-        markers: [
-          'global',
-          'globals',
-          'eslint',
-          'eslint-disable',
-          '*package',
-          '!',
-          ','
-        ]
-      }
-    ],
-    'template-curly-spacing': [2, 'never'],
-    'use-isnan': 2,
-    'valid-typeof': 2,
-    'wrap-iife': [2, 'any'],
-    'yield-star-spacing': [2, 'both'],
-    yoda: [2, 'never'],
-    'prefer-const': 2,
-    'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
-    'object-curly-spacing': [
-      2,
-      'always',
-      {
-        objectsInObjects: false
-      }
-    ],
-    'array-bracket-spacing': [2, 'never']
-  }
+  //   // add your custom rules here
+  //   //it is base on https://github.com/vuejs/eslint-config-vue
+  //   // rules: {
+  //   //   'vue/html-self-closing': [
+  //   //     0,
+  //   //     {
+  //   //       html: {
+  //   //         void: 'always',
+  //   //         normal: 'never',
+  //   //         component: 'always'
+  //   //       },
+  //   //       svg: 'always',
+  //   //       math: 'always'
+  //   //     }
+  //   //   ],
+  //   //   'vue/max-attributes-per-line': [
+  //   //     2,
+  //   //     {
+  //   //       singleline: 10,
+  //   //       multiline: {
+  //   //         max: 1,
+  //   //         allowFirstLine: false
+  //   //       }
+  //   //     }
+  //   //   ],
+  //   //   'vue/singleline-html-element-content-newline': 'off',
+  //   //   'vue/multiline-html-element-content-newline': 'off',
+  //   //   'vue/name-property-casing': ['error', 'PascalCase'],
+  //   //   'vue/no-v-html': 'off',
+  //   //   'accessor-pairs': 2,
+  //   //   'arrow-spacing': [
+  //   //     2,
+  //   //     {
+  //   //       before: true,
+  //   //       after: true
+  //   //     }
+  //   //   ],
+  //   //   'block-spacing': [2, 'always'],
+  //   //   'brace-style': [
+  //   //     2,
+  //   //     '1tbs',
+  //   //     {
+  //   //       allowSingleLine: true
+  //   //     }
+  //   //   ],
+  //   //   camelcase: [
+  //   //     0,
+  //   //     {
+  //   //       properties: 'always'
+  //   //     }
+  //   //   ],
+  //   //   'comma-dangle': [2, 'never'],
+  //   //   'comma-spacing': [
+  //   //     2,
+  //   //     {
+  //   //       before: false,
+  //   //       after: true
+  //   //     }
+  //   //   ],
+  //   //   'comma-style': [2, 'last'],
+  //   //   'constructor-super': 2,
+  //   //   curly: [2, 'multi-line'],
+  //   //   'dot-location': [2, 'property'],
+  //   //   'eol-last': 2,
+  //   //   eqeqeq: [
+  //   //     'error',
+  //   //     'always',
+  //   //     {
+  //   //       null: 'ignore'
+  //   //     }
+  //   //   ],
+  //   //   'generator-star-spacing': [
+  //   //     2,
+  //   //     {
+  //   //       before: true,
+  //   //       after: true
+  //   //     }
+  //   //   ],
+  //   //   'handle-callback-err': [2, '^(err|error)$'],
+  //   //   indent: [
+  //   //     2,
+  //   //     2,
+  //   //     {
+  //   //       SwitchCase: 1
+  //   //     }
+  //   //   ],
+  //   //   'jsx-quotes': [2, 'prefer-single'],
+  //   //   'key-spacing': [
+  //   //     2,
+  //   //     {
+  //   //       beforeColon: false,
+  //   //       afterColon: true
+  //   //     }
+  //   //   ],
+  //   //   'keyword-spacing': [
+  //   //     2,
+  //   //     {
+  //   //       before: true,
+  //   //       after: true
+  //   //     }
+  //   //   ],
+  //   //   'new-cap': [
+  //   //     2,
+  //   //     {
+  //   //       newIsCap: true,
+  //   //       capIsNew: false
+  //   //     }
+  //   //   ],
+  //   //   'new-parens': 2,
+  //   //   'no-array-constructor': 2,
+  //   //   'no-caller': 2,
+  //   //   'no-console': 'off',
+  //   //   'no-class-assign': 2,
+  //   //   'no-cond-assign': 2,
+  //   //   'no-const-assign': 2,
+  //   //   'no-control-regex': 0,
+  //   //   'no-delete-var': 2,
+  //   //   'no-dupe-args': 2,
+  //   //   'no-dupe-class-members': 2,
+  //   //   'no-dupe-keys': 2,
+  //   //   'no-duplicate-case': 2,
+  //   //   'no-empty-character-class': 2,
+  //   //   'no-empty-pattern': 2,
+  //   //   'no-eval': 2,
+  //   //   'no-ex-assign': 2,
+  //   //   'no-extend-native': 2,
+  //   //   'no-extra-bind': 2,
+  //   //   'no-extra-boolean-cast': 2,
+  //   //   'no-extra-parens': [2, 'functions'],
+  //   //   'no-fallthrough': 2,
+  //   //   'no-floating-decimal': 2,
+  //   //   'no-func-assign': 2,
+  //   //   'no-implied-eval': 2,
+  //   //   'no-inner-declarations': [2, 'functions'],
+  //   //   'no-invalid-regexp': 2,
+  //   //   'no-irregular-whitespace': 2,
+  //   //   'no-iterator': 2,
+  //   //   'no-label-var': 2,
+  //   //   'no-labels': [
+  //   //     0,
+  //   //     {
+  //   //       allowLoop: true,
+  //   //       allowSwitch: true
+  //   //     }
+  //   //   ],
+  //   //   'no-lone-blocks': 2,
+  //   //   'no-mixed-spaces-and-tabs': 2,
+  //   //   'no-multi-spaces': 2,
+  //   //   'no-multi-str': 2,
+  //   //   'no-multiple-empty-lines': [
+  //   //     2,
+  //   //     {
+  //   //       max: 1
+  //   //     }
+  //   //   ],
+  //   //   'no-native-reassign': 2,
+  //   //   'no-negated-in-lhs': 2,
+  //   //   'no-new-object': 2,
+  //   //   'no-new-require': 2,
+  //   //   'no-new-symbol': 2,
+  //   //   'no-new-wrappers': 2,
+  //   //   'no-obj-calls': 2,
+  //   //   'no-octal': 2,
+  //   //   'no-octal-escape': 2,
+  //   //   'no-path-concat': 2,
+  //   //   'no-proto': 2,
+  //   //   'no-redeclare': 2,
+  //   //   'no-regex-spaces': 2,
+  //   //   'no-return-assign': [2, 'except-parens'],
+  //   //   'no-self-assign': 2,
+  //   //   'no-self-compare': 2,
+  //   //   'no-sequences': 2,
+  //   //   'no-shadow-restricted-names': 2,
+  //   //   'no-spaced-func': 2,
+  //   //   'no-sparse-arrays': 2,
+  //   //   'no-this-before-super': 2,
+  //   //   'no-throw-literal': 2,
+  //   //   'no-trailing-spaces': 2,
+  //   //   'no-undef': 2,
+  //   //   'no-undef-init': 2,
+  //   //   'no-unexpected-multiline': 2,
+  //   //   'no-unmodified-loop-condition': 2,
+  //   //   'no-unneeded-ternary': [
+  //   //     2,
+  //   //     {
+  //   //       defaultAssignment: false
+  //   //     }
+  //   //   ],
+  //   //   'no-unreachable': 2,
+  //   //   'no-unsafe-finally': 2,
+  //   //   'no-unused-vars': [
+  //   //     2,
+  //   //     {
+  //   //       vars: 'all',
+  //   //       args: 'none'
+  //   //     }
+  //   //   ],
+  //   //   'no-useless-call': 2,
+  //   //   'no-useless-computed-key': 2,
+  //   //   'no-useless-constructor': 2,
+  //   //   'no-useless-escape': 0,
+  //   //   'no-whitespace-before-property': 2,
+  //   //   'no-with': 2,
+  //   //   'one-var': [
+  //   //     2,
+  //   //     {
+  //   //       initialized: 'never'
+  //   //     }
+  //   //   ],
+  //   //   'operator-linebreak': [
+  //   //     2,
+  //   //     'after',
+  //   //     {
+  //   //       overrides: {
+  //   //         '?': 'before',
+  //   //         ':': 'before'
+  //   //       }
+  //   //     }
+  //   //   ],
+  //   //   'padded-blocks': [2, 'never'],
+  //   //   quotes: [
+  //   //     2,
+  //   //     'single',
+  //   //     {
+  //   //       avoidEscape: true,
+  //   //       allowTemplateLiterals: true
+  //   //     }
+  //   //   ],
+  //   //   semi: [0, 'never'],
+  //   //   'semi-spacing': [
+  //   //     0,
+  //   //     {
+  //   //       before: false,
+  //   //       after: true
+  //   //     }
+  //   //   ],
+  //   //   'space-before-blocks': [2, 'always'],
+  //   //   'space-before-function-paren': [2, 'never'],
+  //   //   'space-in-parens': [2, 'never'],
+  //   //   'space-infix-ops': 2,
+  //   //   'space-unary-ops': [
+  //   //     2,
+  //   //     {
+  //   //       words: true,
+  //   //       nonwords: false
+  //   //     }
+  //   //   ],
+  //   //   'spaced-comment': [
+  //   //     2,
+  //   //     'always',
+  //   //     {
+  //   //       markers: [
+  //   //         'global',
+  //   //         'globals',
+  //   //         'eslint',
+  //   //         'eslint-disable',
+  //   //         '*package',
+  //   //         '!',
+  //   //         ','
+  //   //       ]
+  //   //     }
+  //   //   ],
+  //   //   'template-curly-spacing': [2, 'never'],
+  //   //   'use-isnan': 2,
+  //   //   'valid-typeof': 2,
+  //   //   'wrap-iife': [2, 'any'],
+  //   //   'yield-star-spacing': [2, 'both'],
+  //   //   yoda: [2, 'never'],
+  //   //   'prefer-const': 2,
+  //   //   'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
+  //   //   'object-curly-spacing': [
+  //   //     2,
+  //   //     'always',
+  //   //     {
+  //   //       objectsInObjects: false
+  //   //     }
+  //   //   ],
+  //   //   'array-bracket-spacing': [2, 'never']
+  //   // }
 };

+ 9 - 0
.prettierrc

@@ -0,0 +1,9 @@
+{
+    "printWidth": 80,
+    "tabWidth": 2,
+    "singleQuote": true,
+    "trailingComma": "none",
+    "bracketSpacing": true,
+    "arrowParens": "avoid",
+    "htmlWhitespaceSensitivity": "css"
+}

+ 1 - 1
package.json

@@ -39,7 +39,7 @@
     "chalk": "2.4.2",
     "connect": "3.6.6",
     "eslint": "6.7.2",
-    "eslint-plugin-vue": "6.2.2",
+    "eslint-plugin-vue": "^6.2.2",
     "html-webpack-plugin": "3.2.0",
     "mockjs": "1.0.1-beta3",
     "runjs": "4.3.2",

+ 161 - 0
src/components/BaseTable.vue

@@ -0,0 +1,161 @@
+<template>
+  <div class="mt-20">
+    <el-table
+      :data="items"
+      :style="`width: 100%; min-height:${minHeight};`"
+      v-bind="$attrs"
+      @selection-change="handleSelectionChange"
+    >
+      <slot name="table">
+        <template v-for="column in columns">
+          <el-table-column
+            v-if="column.key === 'selection'"
+            :key="column.key"
+            :type="column.key"
+            :min-width="column.minWidth"
+            :width="column.width || 50"
+            :align="column.align || 'center'"
+          />
+          <el-table-column
+            v-else
+            :key="column.key"
+            :prop="column.key"
+            :label="column.name"
+            :min-width="column.minWidth"
+            :width="column.width"
+            :align="column.align"
+            :fixed="column.fixed"
+            :show-overflow-tooltip="column['show-overflow-tooltip']"
+          >
+            <template slot-scope="scope">
+              <ex-slot
+                v-if="column.render"
+                :render="column.render"
+                :row="scope.row"
+                :index="scope.$index"
+                :column="column"
+              />
+              <span v-else-if="column.type === 'tag'">
+                <el-tag
+                  size="medium"
+                  :type="column.fetchTagType(scope.row[column.key]) || ''"
+                  >{{ scope.row[column.key] }}</el-tag
+                >
+              </span>
+              <span v-else>{{ scope.row[column.key] || '-' }}</span>
+            </template>
+          </el-table-column>
+        </template>
+      </slot>
+    </el-table>
+    <div class="page-select">
+      <div class="btn-box">
+        <slot :selected="multipleSelection" name="btn-box" />
+      </div>
+      <el-pagination
+        v-if="showPage"
+        background
+        layout="prev, pager, next"
+        :current-page="pagination.page"
+        :page-size="pagination.pageSize"
+        :total="pagination.total"
+        @current-change="num => pageChange(num)"
+      />
+    </div>
+  </div>
+</template>
+
+<script>
+// 自定义内容的组件
+var exSlot = {
+  functional: true,
+  props: {
+    row: Object,
+    render: Function,
+    index: Number,
+    column: {
+      type: Object,
+      default: null
+    }
+  },
+
+  render: (h, data) => {
+    const params = {
+      row: data.props.row,
+      index: data.props.index
+    };
+
+    if (data.props.column) params.column = data.props.column;
+    return data.props.render(h, params);
+  }
+};
+
+export default {
+  name: 'TableWithPage',
+
+  components: {
+    'ex-slot': exSlot
+  },
+
+  props: {
+    columns: {
+      type: Array,
+      default: () => []
+    },
+    items: {
+      type: Array,
+      default: () => []
+    },
+    pagination: {
+      type: Object,
+      default: () => ({})
+    },
+    pageChange: {
+      type: Function,
+      default: () => {}
+    },
+    minHeight: {
+      type: String,
+      default: '600px'
+    },
+    showPage: {
+      type: Boolean,
+      default: true
+    }
+  },
+
+  data() {
+    return {
+      multipleSelection: []
+    };
+  },
+
+  watch: {
+    items: {
+      handler(val) {
+        this.multipleSelection = [];
+      },
+      immedaite: true
+    }
+  },
+
+  methods: {
+    handleSelectionChange(params) {
+      this.multipleSelection = params;
+    }
+  }
+};
+</script>
+
+<style scoped>
+.page-select {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 6px 20px 0 20px;
+}
+
+.btn-box .el-button {
+  margin: 2px 10px;
+}
+</style>

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


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


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


+ 10 - 0
src/components/index.js

@@ -0,0 +1,10 @@
+import Vue from 'vue';
+import BaseTable from './BaseTable.vue';
+import Breadcrumb from './Breadcrumb.vue';
+import Hamburger from './Hamburger.vue';
+import SvgIcon from './SvgIcon.vue';
+
+Vue.component('BaseTable', BaseTable);
+Vue.component('Breadcrumb', Breadcrumb);
+Vue.component('Hamburger', Hamburger);
+Vue.component('SvgIcon', SvgIcon);

+ 35 - 0
src/components/inject.js

@@ -0,0 +1,35 @@
+const glob = require('glob');
+const fs = require('fs');
+const filenames = [];
+var entryFiles = glob.sync('./**/*.vue');
+entryFiles.forEach(filePath => {
+  filenames.push(filePath);
+});
+const getImportItemStr = path => {
+  const filename = path.substring(
+    path.lastIndexOf('/') + 1,
+    path.lastIndexOf('.')
+  );
+  return `import ${filename} from '${path}';`;
+};
+const getRegistItemStr = path => {
+  const filename = path.substring(
+    path.lastIndexOf('/') + 1,
+    path.lastIndexOf('.')
+  );
+  return `Vue.component('${filename}', ${filename});`;
+};
+
+const content = [
+  `import Vue from 'vue';`,
+  '\r\n',
+  filenames.map(x => getImportItemStr(x)).join('\r\n'),
+  '\r\n\r\n',
+  filenames.map(x => getRegistItemStr(x)).join('\r\n'),
+  '\r\n'
+];
+
+fs.writeFile('./index.js', content.join(''), function(err) {
+  if (err) console.log(err);
+  else console.log('写文件操作成功');
+});

+ 184 - 0
src/containers/ToolbarContainer.vue

@@ -0,0 +1,184 @@
+<template>
+  <el-form label-position="right" label-width="0" :model="form">
+    <el-row :gutter="20">
+      <el-col
+        v-for="field in fields"
+        :key="field.name"
+        :span="field.col || 8"
+        class="h-70"
+      >
+        <el-form-item
+          :label="field.label"
+          :label-width="
+            field.labelWidth ? field.labelWidth : field.label && '80px'
+          "
+        >
+          <!-- 输入文本 -->
+          <el-input
+            v-if="field.type === 'text'"
+            v-model="form[field.name]"
+            :clearable="true"
+            :placeholder="'请输入' + field.label"
+          />
+
+          <!-- 单选 -->
+          <el-select
+            v-if="field.type === 'select'"
+            v-model="form[field.name]"
+            :clearable="true"
+            :placeholder="'请选择' + field.label"
+          >
+            <el-option
+              v-for="item in field.options"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            >
+            </el-option>
+          </el-select>
+
+          <!-- 多选 -->
+          <el-select
+            v-if="field.type === 'multipleSelect'"
+            v-model="form[field.name]"
+            multiple
+            collapse-tags
+            :clearable="true"
+            :placeholder="'请选择' + field.label"
+          >
+            <el-option
+              v-for="item in field.options"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            >
+            </el-option>
+          </el-select>
+
+          <!-- 时间选择器 -->
+          <el-date-picker
+            v-if="field.type === 'dateArray'"
+            v-model="form[field.name]"
+            type="datetimerange"
+            start-placeholder="开始日期"
+            end-placeholder="结束日期"
+          >
+          </el-date-picker>
+        </el-form-item>
+      </el-col>
+    </el-row>
+    <div class="f-fe-c prow-10">
+      <el-button v-if="showSearch" type="primary" @click="handleSubmit"
+        >查询</el-button
+      >
+      <el-button v-if="showReset" @click="handleReset">重置</el-button>
+    </div>
+  </el-form>
+</template>
+
+<script>
+function isPromise(obj) {
+  return (
+    !!obj &&
+    (typeof obj === 'object' || typeof obj === 'function') &&
+    typeof obj.then === 'function'
+  );
+}
+export default {
+  name: 'Toolbar',
+
+  props: {
+    fields: {
+      type: Array,
+      default: () => []
+    },
+    showSearch: {
+      type: Boolean,
+      default: true
+    },
+    showReset: {
+      type: Boolean,
+      default: true
+    },
+    firstLoad: {
+      type: Boolean,
+      default: true
+    }
+  },
+
+  data() {
+    return {
+      form: {}
+    };
+  },
+
+  mounted() {
+    if (this.firstLoad) {
+      this.handleReset();
+    } else {
+      this.initForm();
+    }
+  },
+
+  methods: {
+    handleSubmit() {
+      const filter = this.getFormData();
+      this.$emit('on-filter', filter);
+    },
+
+    async handleReset() {
+      await this.initForm();
+      const filter = this.getFormData();
+      this.$emit('on-reset', filter);
+    },
+
+    async initForm() {
+      const form = this.fields.reduce(async (init, current) => {
+        init = await init;
+        init[current.name] = current.defaultValue || null;
+
+        if (current.options && isPromise(current.options)) {
+          current.options = await current.options;
+        }
+
+        return init;
+      }, Promise.resolve({}));
+      this.form = await form;
+    },
+
+    getFormData() {
+      const filter = this.fields.reduce(
+        (init, { name, apiName, type, format }) => {
+          const values = this.form[name];
+          const key = apiName || name;
+          let temp = null;
+
+          if (type === 'dateArray') {
+            temp = [];
+            apiName.forEach((x, i) => {
+              temp.push(values && values[i]);
+            });
+          } else {
+            temp = values || values === 0 ? values : null;
+          }
+          const val = format ? format(values, temp) : temp;
+          if (typeof key === 'string') {
+            init[key] = val;
+          } else {
+            key.forEach((x, i) => {
+              init[x] = val[i];
+            });
+          }
+          return init;
+        }
+      );
+    }
+  }
+};
+</script>
+
+<style scoped lang="scss">
+.h-70 {
+  height: 70px;
+}
+</style>

+ 4 - 0
src/containers/index.js

@@ -0,0 +1,4 @@
+import Vue from 'vue';
+import ToolbarContainer from './ToolbarContainer.vue';
+
+Vue.component('ToolbarContainer', ToolbarContainer);

+ 35 - 0
src/containers/inject.js

@@ -0,0 +1,35 @@
+const glob = require('glob');
+const fs = require('fs');
+const filenames = [];
+var entryFiles = glob.sync('./**/*.vue');
+entryFiles.forEach(filePath => {
+  filenames.push(filePath);
+});
+const getImportItemStr = path => {
+  const filename = path.substring(
+    path.lastIndexOf('/') + 1,
+    path.lastIndexOf('.')
+  );
+  return `import ${filename} from '${path}';`;
+};
+const getRegistItemStr = path => {
+  const filename = path.substring(
+    path.lastIndexOf('/') + 1,
+    path.lastIndexOf('.')
+  );
+  return `Vue.component('${filename}', ${filename});`;
+};
+
+const content = [
+  `import Vue from 'vue';`,
+  '\r\n',
+  filenames.map(x => getImportItemStr(x)).join('\r\n'),
+  '\r\n\r\n',
+  filenames.map(x => getRegistItemStr(x)).join('\r\n'),
+  '\r\n'
+];
+
+fs.writeFile('./index.js', content.join(''), function(err) {
+  if (err) console.log(err);
+  else console.log('写文件操作成功');
+});

+ 4 - 3
src/layout/components/AppMain.vue

@@ -11,10 +11,10 @@ export default {
   name: 'AppMain',
   computed: {
     key() {
-      return this.$route.path
+      return this.$route.path;
     }
   }
-}
+};
 </script>
 
 <style scoped>
@@ -24,8 +24,9 @@ export default {
   width: 100%;
   position: relative;
   overflow: hidden;
+  background-color: #eceeef;
 }
-.fixed-header+.app-main {
+.fixed-header + .app-main {
   padding-top: 50px;
 }
 </style>

+ 0 - 6
src/layout/components/Navbar.vue

@@ -38,14 +38,8 @@
 
 <script>
 import { mapGetters } from 'vuex';
-import Breadcrumb from '@/components/Breadcrumb';
-import Hamburger from '@/components/Hamburger';
 
 export default {
-  components: {
-    Breadcrumb,
-    Hamburger
-  },
   computed: {
     ...mapGetters(['sidebar', 'avatar', 'name'])
   },

+ 3 - 0
src/main.js

@@ -15,6 +15,9 @@ import router from './router'
 import '@/icons' // icon
 import '@/permission' // permission control
 
+import './components';
+import './containers';
+
 /**
  * If you don't want to use mock-server
  * you want to use MockJs for mock api

+ 73 - 0
src/mixins/filterList.js

@@ -0,0 +1,73 @@
+import { Message } from 'element-ui';
+// import tips from 'utils/tips'
+const filterList = (params = {}) => ({
+  data() {
+    return {
+      isLoading: false,
+      items: [],
+      pagination: {
+        page: 1,
+        total: 0,
+        pageSize: 50
+      },
+      filter: {}, // 每次填写的过滤条件
+      internalFilterObj: {}, // 必定的内置过滤条件
+      fetchList: () => {}
+    };
+  },
+
+  created() {
+    Object.assign(this, params);
+  },
+
+  methods: {
+    loadCallBack() {},
+
+    apiList(data) {
+      return this.fetchList(data);
+    },
+
+    reload() {
+      this.pageChange(this.pagination.page);
+    },
+
+    async pageChange(page) {
+      this.pagination.page = page;
+      const inParams = {
+        ...this.filter,
+        ...this.internalFilterObj,
+        page: this.pagination.page,
+        size: this.pagination.pageSize
+      };
+
+      const { data, message } = await this.apiList(inParams);
+      if (data) {
+        const items = data.data;
+        const total = {
+          page: data.page,
+          pageSize: data.size,
+          total: data.total
+        };
+        if (items.length === 0 && this.pagination.page > 1) {
+          this.pageChange(1);
+        } else {
+          this.items = items;
+          this.pagination = total;
+        }
+        this.loadCallBack(data);
+      } else {
+        Message({
+          message: message,
+          type: 'error',
+          duration: 5 * 1000
+        });
+      }
+    },
+
+    filterData(filter) {
+      this.filter = filter;
+      this.pageChange(1);
+    }
+  }
+});
+export default filterList;

+ 8 - 0
src/styles/common.scss

@@ -87,3 +87,11 @@ $ais: (
     min-width: 0;
   }
 }
+
+.bg-w {
+  background-color: #fff;
+}
+
+.br-10 {
+  border-radius: 10px;
+}

+ 20 - 0
src/utils/params.js

@@ -0,0 +1,20 @@
+const format = (params) => {
+  const keys = Object.keys(params);
+  if (!keys.length) {
+    return {};
+  }
+  return keys.reduce((initObj, key) => {
+    let val = params[key];
+    if (typeof (val) === 'string') {
+      val = val.trim();
+    }
+    if (val !== null && val !== undefined && val !== '') {
+      initObj[key] = val;
+    }
+    return initObj;
+  }, {});
+};
+
+export {
+  format
+};

+ 9 - 4
src/utils/request.js

@@ -110,7 +110,6 @@ const formatResponse = fetchResult =>
  * 格式化status
  */
 const formatStatus = response => {
-  console.error(response);
   // 如果http状态码正常,则直接返回数据
   if (response && (response.code === 200 || response.code === 20000)) {
     response.success = true;
@@ -261,7 +260,9 @@ const get = (url, data = {}, config) => {
       ...config,
       params: data,
       paramsSerializer(params) {
-        return qs.stringify(params, { arrayFormat: 'brackets' });
+        return qs.stringify(params, {
+          arrayFormat: 'brackets'
+        });
       }
     })
   );
@@ -274,7 +275,9 @@ const del = (url, data = {}, config, type) => {
       ...config,
       params: data,
       paramsSerializer(params) {
-        return qs.stringify(params, { arrayFormat: 'brackets' });
+        return qs.stringify(params, {
+          arrayFormat: 'brackets'
+        });
       }
     })
   );
@@ -288,7 +291,9 @@ const delData = (url, data = {}, params, config) => {
       data: data,
       params: params,
       paramsSerializer(params) {
-        return qs.stringify(params, { arrayFormat: 'brackets' });
+        return qs.stringify(params, {
+          arrayFormat: 'brackets'
+        });
       }
     })
   );

+ 94 - 6
src/views/dashboard/index.vue

@@ -1,20 +1,108 @@
 <template>
   <div class="dashboard-container">
-    <div class="dashboard-text">name: {{ name }}</div>
+    <!-- <div class="dashboard-text">name: {{ name }}</div> -->
+    <div class="bg-w p-20 br-10">
+      <toolbar-container :fields="fields" @on-filter="eee" />
+      <base-table
+        :columns="columns"
+        :items="items"
+        :pagination="pagination"
+        :page-change="pageChange"
+      />
+    </div>
   </div>
 </template>
 
 <script>
-import { mapGetters } from 'vuex'
+import { mapGetters } from 'vuex';
+import mxFilterList from '@/mixins/filterList';
 
 export default {
   name: 'Dashboard',
+
+  mixins: [
+    mxFilterList({
+      fetchList: () => {}
+    })
+  ],
+
   computed: {
-    ...mapGetters([
-      'name'
-    ])
+    ...mapGetters(['name'])
+  },
+  data() {
+    return {
+      fields: [
+        {
+          type: 'dateArray',
+          name: 'paidTime',
+          label: '收款时间',
+          apiName: ['start', 'end'],
+          defaultValue: [,]
+        },
+
+        {
+          type: 'text',
+          name: 'paidTime2',
+          label: '收款时间',
+          defaultValue: 'fick'
+        },
+        {
+          type: 'text',
+          name: 'paidTime3',
+          label: '收款时间',
+          defaultValue: 'fick'
+        }
+      ],
+      columns: [
+        {
+          key: 'region',
+          name: '大区',
+          width: '120'
+        },
+        {
+          key: 'province',
+          name: '省',
+          width: '120'
+        },
+        {
+          key: 'city',
+          name: '市',
+          width: '150'
+        },
+        {
+          key: 'area',
+          name: '区',
+          minWidth: '100'
+        },
+        {
+          key: 'storeChain',
+          name: '连锁',
+          minWidth: '100'
+        },
+        {
+          key: 'storeName',
+          name: '门店',
+          minWidth: '100'
+        },
+        {
+          key: 'coupons',
+          name: '发行码数',
+          width: '100'
+        },
+        {
+          key: 'writeoff',
+          name: '核销数',
+          width: '100'
+        }
+      ]
+    };
+  },
+  methods: {
+    eee() {
+      console.warn('-------');
+    }
   }
-}
+};
 </script>
 
 <style lang="scss" scoped>

+ 62 - 48
vue.config.js

@@ -1,19 +1,19 @@
-'use strict'
-const path = require('path')
-const defaultSettings = require('./src/settings.js')
+'use strict';
+const path = require('path');
+const defaultSettings = require('./src/settings.js');
 
 function resolve(dir) {
-  return path.join(__dirname, dir)
+  return path.join(__dirname, dir);
 }
 
-const name = defaultSettings.title || 'vue Admin Template' // page title
+const name = defaultSettings.title || 'vue Admin Template'; // page title
 
 // If your port is set to 80,
 // use administrator privileges to execute the command line.
 // For example, Mac: sudo npm run
 // You can change the port by the following methods:
 // port = 9528 npm run dev OR npm run dev --port = 9528
-const port = process.env.port || process.env.npm_config_port || 9528 // dev port
+const port = process.env.port || process.env.npm_config_port || 9528; // dev port
 
 // All configuration item explanations can be find in https://cli.vuejs.org/config/
 module.exports = {
@@ -58,16 +58,16 @@ module.exports = {
         fileBlacklist: [/\.map$/, /hot-update\.js$/, /runtime\..*\.js$/],
         include: 'initial'
       }
-    ])
+    ]);
 
     // when there are many pages, it will cause too many meaningless requests
-    config.plugins.delete('prefetch')
+    config.plugins.delete('prefetch');
 
     // set svg-sprite-loader
     config.module
       .rule('svg')
       .exclude.add(resolve('src/icons'))
-      .end()
+      .end();
     config.module
       .rule('icons')
       .test(/\.svg$/)
@@ -78,46 +78,60 @@ module.exports = {
       .options({
         symbolId: 'icon-[name]'
       })
-      .end()
+      .end();
 
-    config
-      .when(process.env.NODE_ENV !== 'development',
-        config => {
-          config
-            .plugin('ScriptExtHtmlWebpackPlugin')
-            .after('html')
-            .use('script-ext-html-webpack-plugin', [{
+    config.resolve.alias
+      .set('api', path.resolve('src/api'))
+      .set('assets', path.resolve('src/assets'))
+      .set('components', path.resolve('src/components'))
+      .set('config', path.resolve('src/config'))
+      .set('const', path.resolve('src/const'))
+      .set('containers', path.resolve('src/containers'))
+      .set('directives', path.resolve('src/directives'))
+      .set('mixins', path.resolve('src/mixins'))
+      .set('model', path.resolve('src/model'))
+      .set('plugins', path.resolve('src/plugins'))
+      .set('src', path.resolve('src'))
+      .set('store', path.resolve('src/store'))
+      .set('utils', path.resolve('src/utils'))
+      .set('views', path.resolve('src/views'));
+
+    config.when(process.env.NODE_ENV !== 'development', (config) => {
+      config
+        .plugin('ScriptExtHtmlWebpackPlugin')
+        .after('html')
+        .use('script-ext-html-webpack-plugin', [
+          {
             // `runtime` must same as runtimeChunk name. default is `runtime`
-              inline: /runtime\..*\.js$/
-            }])
-            .end()
-          config
-            .optimization.splitChunks({
-              chunks: 'all',
-              cacheGroups: {
-                libs: {
-                  name: 'chunk-libs',
-                  test: /[\\/]node_modules[\\/]/,
-                  priority: 10,
-                  chunks: 'initial' // only package third parties that are initially dependent
-                },
-                elementUI: {
-                  name: 'chunk-elementUI', // split elementUI into a single package
-                  priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
-                  test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm
-                },
-                commons: {
-                  name: 'chunk-commons',
-                  test: resolve('src/components'), // can customize your rules
-                  minChunks: 3, //  minimum common number
-                  priority: 5,
-                  reuseExistingChunk: true
-                }
-              }
-            })
-          // https:// webpack.js.org/configuration/optimization/#optimizationruntimechunk
-          config.optimization.runtimeChunk('single')
+            inline: /runtime\..*\.js$/
+          }
+        ])
+        .end();
+      config.optimization.splitChunks({
+        chunks: 'all',
+        cacheGroups: {
+          libs: {
+            name: 'chunk-libs',
+            test: /[\\/]node_modules[\\/]/,
+            priority: 10,
+            chunks: 'initial' // only package third parties that are initially dependent
+          },
+          elementUI: {
+            name: 'chunk-elementUI', // split elementUI into a single package
+            priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
+            test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm
+          },
+          commons: {
+            name: 'chunk-commons',
+            test: resolve('src/components'), // can customize your rules
+            minChunks: 3, //  minimum common number
+            priority: 5,
+            reuseExistingChunk: true
+          }
         }
-      )
+      });
+      // https:// webpack.js.org/configuration/optimization/#optimizationruntimechunk
+      config.optimization.runtimeChunk('single');
+    });
   }
-}
+};