正在显示
40 个修改的文件
包含
2700 行增加
和
29 行删除
package-lock.json
0 → 100644
此 diff 太大无法显示。
| @@ -10,16 +10,18 @@ | @@ -10,16 +10,18 @@ | ||
| 10 | "build": "node build/build.js" | 10 | "build": "node build/build.js" |
| 11 | }, | 11 | }, |
| 12 | "dependencies": { | 12 | "dependencies": { |
| 13 | - "axios": "^0.15.3", | 13 | + "axios": "^0.19.0", |
| 14 | "echarts": "^3.3.2", | 14 | "echarts": "^3.3.2", |
| 15 | "element-ui": "^1.2.8", | 15 | "element-ui": "^1.2.8", |
| 16 | "eslint": "^5.14.1", | 16 | "eslint": "^5.14.1", |
| 17 | "font-awesome": "^4.7.0", | 17 | "font-awesome": "^4.7.0", |
| 18 | "install": "^0.12.2", | 18 | "install": "^0.12.2", |
| 19 | + "js-cookie": "^2.2.1", | ||
| 19 | "moment": "^2.24.0", | 20 | "moment": "^2.24.0", |
| 20 | "npm": "^6.8.0", | 21 | "npm": "^6.8.0", |
| 21 | "nprogress": "^0.2.0", | 22 | "nprogress": "^0.2.0", |
| 22 | "vue": "^2.2.2", | 23 | "vue": "^2.2.2", |
| 24 | + "vue-i18n": "^8.14.0", | ||
| 23 | "vue-router": "^2.3.0", | 25 | "vue-router": "^2.3.0", |
| 24 | "vuex": "^2.0.0-rc.6" | 26 | "vuex": "^2.0.0-rc.6" |
| 25 | }, | 27 | }, |
| @@ -45,7 +47,7 @@ | @@ -45,7 +47,7 @@ | ||
| 45 | "friendly-errors-webpack-plugin": "^1.1.3", | 47 | "friendly-errors-webpack-plugin": "^1.1.3", |
| 46 | "function-bind": "^1.0.2", | 48 | "function-bind": "^1.0.2", |
| 47 | "html-webpack-plugin": "^2.28.0", | 49 | "html-webpack-plugin": "^2.28.0", |
| 48 | - "http-proxy-middleware": "^0.17.3", | 50 | + "http-proxy-middleware": "^0.19.1", |
| 49 | "json-loader": "^0.5.4", | 51 | "json-loader": "^0.5.4", |
| 50 | "mockjs": "^1.0.1-beta3", | 52 | "mockjs": "^1.0.1-beta3", |
| 51 | "node-sass": "^4.5.0", | 53 | "node-sass": "^4.5.0", |
| @@ -62,7 +64,7 @@ | @@ -62,7 +64,7 @@ | ||
| 62 | "vue-style-loader": "^2.0.0", | 64 | "vue-style-loader": "^2.0.0", |
| 63 | "vue-template-compiler": "^2.2.4", | 65 | "vue-template-compiler": "^2.2.4", |
| 64 | "webpack": "^2.2.1", | 66 | "webpack": "^2.2.1", |
| 65 | - "webpack-bundle-analyzer": "^2.2.1", | 67 | + "webpack-bundle-analyzer": "^3.4.1", |
| 66 | "webpack-dev-middleware": "^1.10.0", | 68 | "webpack-dev-middleware": "^1.10.0", |
| 67 | "webpack-hot-middleware": "^2.16.1", | 69 | "webpack-hot-middleware": "^2.16.1", |
| 68 | "webpack-merge": "^2.6.1" | 70 | "webpack-merge": "^2.6.1" |
| @@ -75,5 +77,11 @@ | @@ -75,5 +77,11 @@ | ||
| 75 | "> 1%", | 77 | "> 1%", |
| 76 | "last 2 versions", | 78 | "last 2 versions", |
| 77 | "not ie <= 8" | 79 | "not ie <= 8" |
| 78 | - ] | 80 | + ], |
| 81 | + "main": ".eslintrc.js", | ||
| 82 | + "repository": { | ||
| 83 | + "type": "git", | ||
| 84 | + "url": "git@118.31.66.166:zp260/vue_cli.git" | ||
| 85 | + }, | ||
| 86 | + "keywords": [] | ||
| 79 | } | 87 | } |
src/components/Pagination/index.vue
0 → 100755
| 1 | +<template> | ||
| 2 | + <div :class="{'hidden':hidden}" class="pagination-container"> | ||
| 3 | + <el-pagination | ||
| 4 | + :background="background" | ||
| 5 | + :current-page.sync="currentPage" | ||
| 6 | + :page-size.sync="pageSize" | ||
| 7 | + :layout="layout" | ||
| 8 | + :page-sizes="pageSizes" | ||
| 9 | + :total="total" | ||
| 10 | + v-bind="$attrs" | ||
| 11 | + @size-change="handleSizeChange" | ||
| 12 | + @current-change="handleCurrentChange"/> | ||
| 13 | + </div> | ||
| 14 | +</template> | ||
| 15 | + | ||
| 16 | +<script> | ||
| 17 | +import { scrollTo } from '@/utils/scrollTo' | ||
| 18 | + | ||
| 19 | +export default { | ||
| 20 | + name: 'Pagination', | ||
| 21 | + props: { | ||
| 22 | + total: { | ||
| 23 | + required: true, | ||
| 24 | + type: Number | ||
| 25 | + }, | ||
| 26 | + page: { | ||
| 27 | + type: Number, | ||
| 28 | + default: 1 | ||
| 29 | + }, | ||
| 30 | + limit: { | ||
| 31 | + type: Number, | ||
| 32 | + default: 20 | ||
| 33 | + }, | ||
| 34 | + pageSizes: { | ||
| 35 | + type: Array, | ||
| 36 | + default() { | ||
| 37 | + return [10, 20, 30, 50] | ||
| 38 | + } | ||
| 39 | + }, | ||
| 40 | + layout: { | ||
| 41 | + type: String, | ||
| 42 | + default: 'total, sizes, prev, pager, next, jumper' | ||
| 43 | + }, | ||
| 44 | + background: { | ||
| 45 | + type: Boolean, | ||
| 46 | + default: true | ||
| 47 | + }, | ||
| 48 | + autoScroll: { | ||
| 49 | + type: Boolean, | ||
| 50 | + default: true | ||
| 51 | + }, | ||
| 52 | + hidden: { | ||
| 53 | + type: Boolean, | ||
| 54 | + default: false | ||
| 55 | + } | ||
| 56 | + }, | ||
| 57 | + computed: { | ||
| 58 | + currentPage: { | ||
| 59 | + get() { | ||
| 60 | + return this.page | ||
| 61 | + }, | ||
| 62 | + set(val) { | ||
| 63 | + this.$emit('update:page', val) | ||
| 64 | + } | ||
| 65 | + }, | ||
| 66 | + pageSize: { | ||
| 67 | + get() { | ||
| 68 | + return this.limit | ||
| 69 | + }, | ||
| 70 | + set(val) { | ||
| 71 | + this.$emit('update:limit', val) | ||
| 72 | + } | ||
| 73 | + } | ||
| 74 | + }, | ||
| 75 | + methods: { | ||
| 76 | + handleSizeChange(val) { | ||
| 77 | + this.$emit('pagination', { page: this.currentPage, limit: val }) | ||
| 78 | + if (this.autoScroll) { | ||
| 79 | + scrollTo(0, 800) | ||
| 80 | + } | ||
| 81 | + }, | ||
| 82 | + handleCurrentChange(val) { | ||
| 83 | + this.$emit('pagination', { page: val, limit: this.pageSize }) | ||
| 84 | + if (this.autoScroll) { | ||
| 85 | + scrollTo(0, 800) | ||
| 86 | + } | ||
| 87 | + } | ||
| 88 | + } | ||
| 89 | +} | ||
| 90 | +</script> | ||
| 91 | + | ||
| 92 | +<style scoped> | ||
| 93 | +.pagination-container { | ||
| 94 | + background: #fff; | ||
| 95 | + padding: 32px 16px; | ||
| 96 | +} | ||
| 97 | +.pagination-container.hidden { | ||
| 98 | + display: none; | ||
| 99 | +} | ||
| 100 | +</style> |
src/components/TreeTable/eval.js
0 → 100755
| 1 | +/** | ||
| 2 | +* @Author: jianglei | ||
| 3 | +* @Date: 2017-10-12 12:06:49 | ||
| 4 | +*/ | ||
| 5 | +'use strict' | ||
| 6 | +import Vue from 'vue' | ||
| 7 | +export default function treeToArray(data, expandAll, parent = null, level = null) { | ||
| 8 | + let tmp = [] | ||
| 9 | + Array.from(data).forEach(function(record) { | ||
| 10 | + if (record._expanded === undefined) { | ||
| 11 | + Vue.set(record, '_expanded', expandAll) | ||
| 12 | + } | ||
| 13 | + let _level = 1 | ||
| 14 | + if (level !== undefined && level !== null) { | ||
| 15 | + _level = level + 1 | ||
| 16 | + } | ||
| 17 | + Vue.set(record, '_level', _level) | ||
| 18 | + // 如果有父元素 | ||
| 19 | + if (parent) { | ||
| 20 | + Vue.set(record, 'parent', parent) | ||
| 21 | + } | ||
| 22 | + tmp.push(record) | ||
| 23 | + if (record.children && record.children.length > 0) { | ||
| 24 | + const children = treeToArray(record.children, expandAll, record, _level) | ||
| 25 | + tmp = tmp.concat(children) | ||
| 26 | + } | ||
| 27 | + }) | ||
| 28 | + return tmp | ||
| 29 | +} |
src/components/TreeTable/index.vue
0 → 100755
| 1 | +<template> | ||
| 2 | + <el-table :data="formatData" :row-style="showRow" v-bind="$attrs"> | ||
| 3 | + <el-table-column type="selection" width="30" align="center"/> | ||
| 4 | + <el-table-column v-if="columns.length===0" width="30" align="center"> | ||
| 5 | + <template slot-scope="scope"> | ||
| 6 | + <span v-for="space in scope.row._level" :key="space" class="ms-tree-space"/> | ||
| 7 | + <span v-if="iconShow(0,scope.row)" class="tree-ctrl" @click="toggleExpanded(scope.$index)"> | ||
| 8 | + <i v-if="!scope.row._expanded" class="el-icon-plus"/> | ||
| 9 | + <i v-else class="el-icon-minus"/> | ||
| 10 | + </span> | ||
| 11 | + <!--{{ scope.$index }}--> | ||
| 12 | + </template> | ||
| 13 | + </el-table-column> | ||
| 14 | + <el-table-column v-for="(column, index) in columns" v-else :key="column.value" :label="column.text" :width="column.width"> | ||
| 15 | + <template slot-scope="scope"> | ||
| 16 | + <!-- Todo --> | ||
| 17 | + <!-- eslint-disable-next-line vue/no-confusing-v-for-v-if --> | ||
| 18 | + <span v-for="space in scope.row._level" v-if="index === 0" :key="space" class="ms-tree-space"/> | ||
| 19 | + <span v-if="iconShow(index,scope.row)" class="tree-ctrl" @click="toggleExpanded(scope.$index)"> | ||
| 20 | + <i v-if="!scope.row._expanded" class="el-icon-plus"/> | ||
| 21 | + <i v-else class="el-icon-minus"/> | ||
| 22 | + </span> | ||
| 23 | + {{ scope.row[column.value] }} | ||
| 24 | + </template> | ||
| 25 | + </el-table-column> | ||
| 26 | + <slot/> | ||
| 27 | + </el-table> | ||
| 28 | +</template> | ||
| 29 | + | ||
| 30 | +<script> | ||
| 31 | +/** | ||
| 32 | + Auth: Lei.j1ang | ||
| 33 | + Created: 2018/1/19-13:59 | ||
| 34 | +*/ | ||
| 35 | +import treeToArray from './eval' | ||
| 36 | +export default { | ||
| 37 | + name: 'TreeTable', | ||
| 38 | + props: { | ||
| 39 | + /* eslint-disable */ | ||
| 40 | + data: { | ||
| 41 | + type: [Array, Object], | ||
| 42 | + required: true | ||
| 43 | + }, | ||
| 44 | + columns: { | ||
| 45 | + type: Array, | ||
| 46 | + default: () => [] | ||
| 47 | + }, | ||
| 48 | + evalFunc: Function, | ||
| 49 | + evalArgs: Array, | ||
| 50 | + expandAll: { | ||
| 51 | + type: Boolean, | ||
| 52 | + default: true | ||
| 53 | + } | ||
| 54 | + }, | ||
| 55 | + computed: { | ||
| 56 | + // 格式化数据源 | ||
| 57 | + formatData: function() { | ||
| 58 | + let tmp | ||
| 59 | + if (!Array.isArray(this.data)) { | ||
| 60 | + tmp = [this.data] | ||
| 61 | + } else { | ||
| 62 | + tmp = this.data | ||
| 63 | + } | ||
| 64 | + const func = this.evalFunc || treeToArray | ||
| 65 | + const args = this.evalArgs ? Array.concat([tmp, this.expandAll], this.evalArgs) : [tmp, this.expandAll] | ||
| 66 | + return func.apply(null, args) | ||
| 67 | + } | ||
| 68 | + }, | ||
| 69 | + methods: { | ||
| 70 | + showRow: function(row) { | ||
| 71 | + const show = (row.row.parent ? (row.row.parent._expanded && row.row.parent._show) : true) | ||
| 72 | + row.row._show = show | ||
| 73 | + return show ? 'animation:treeTableShow 1s;-webkit-animation:treeTableShow 1s;' : 'display:none;' | ||
| 74 | + }, | ||
| 75 | + // 切换下级是否展开 | ||
| 76 | + toggleExpanded: function(trIndex) { | ||
| 77 | + const record = this.formatData[trIndex] | ||
| 78 | + record._expanded = !record._expanded | ||
| 79 | + }, | ||
| 80 | + // 图标显示 | ||
| 81 | + iconShow(index, record) { | ||
| 82 | + return (index === 0 && record.children && record.children.length > 0) | ||
| 83 | + } | ||
| 84 | + } | ||
| 85 | +} | ||
| 86 | +</script> | ||
| 87 | +<style rel="stylesheet/css"> | ||
| 88 | + @keyframes treeTableShow { | ||
| 89 | + from {opacity: 0;} | ||
| 90 | + to {opacity: 1;} | ||
| 91 | + } | ||
| 92 | + @-webkit-keyframes treeTableShow { | ||
| 93 | + from {opacity: 0;} | ||
| 94 | + to {opacity: 1;} | ||
| 95 | + } | ||
| 96 | +</style> | ||
| 97 | + | ||
| 98 | +<style lang="scss" rel="stylesheet/scss" scoped> | ||
| 99 | + $color-blue: #2196F3; | ||
| 100 | + $space-width: 18px; | ||
| 101 | + .ms-tree-space { | ||
| 102 | + position: relative; | ||
| 103 | + top: 1px; | ||
| 104 | + display: inline-block; | ||
| 105 | + font-style: normal; | ||
| 106 | + font-weight: 400; | ||
| 107 | + line-height: 1; | ||
| 108 | + width: $space-width; | ||
| 109 | + height: 14px; | ||
| 110 | + &::before { | ||
| 111 | + content: "" | ||
| 112 | + } | ||
| 113 | + } | ||
| 114 | + .processContainer{ | ||
| 115 | + width: 100%; | ||
| 116 | + height: 100%; | ||
| 117 | + } | ||
| 118 | + table td { | ||
| 119 | + line-height: 26px; | ||
| 120 | + } | ||
| 121 | + | ||
| 122 | + .tree-ctrl{ | ||
| 123 | + position: relative; | ||
| 124 | + cursor: pointer; | ||
| 125 | + color: $color-blue; | ||
| 126 | + margin-left: -$space-width; | ||
| 127 | + } | ||
| 128 | +</style> |
src/components/TreeTable/readme.md
0 → 100755
| 1 | +## 写在前面 | ||
| 2 | +此组件仅提供一个创建TreeTable的解决思路 | ||
| 3 | + | ||
| 4 | +## prop说明 | ||
| 5 | +#### *data* | ||
| 6 | + **必填** | ||
| 7 | + | ||
| 8 | + 原始数据,要求是一个数组或者对象 | ||
| 9 | + ```javascript | ||
| 10 | + [{ | ||
| 11 | + key1: value1, | ||
| 12 | + key2: value2, | ||
| 13 | + children: [{ | ||
| 14 | + key1: value1 | ||
| 15 | + }, | ||
| 16 | + { | ||
| 17 | + key1: value1 | ||
| 18 | + }] | ||
| 19 | + }, | ||
| 20 | + { | ||
| 21 | + key1: value1 | ||
| 22 | + }] | ||
| 23 | + ``` | ||
| 24 | + 或者 | ||
| 25 | + ```javascript | ||
| 26 | + { | ||
| 27 | + key1: value1, | ||
| 28 | + key2: value2, | ||
| 29 | + children: [{ | ||
| 30 | + key1: value1 | ||
| 31 | + }, | ||
| 32 | + { | ||
| 33 | + key1: value1 | ||
| 34 | + }] | ||
| 35 | + } | ||
| 36 | + ``` | ||
| 37 | + | ||
| 38 | +#### columns | ||
| 39 | + 列属性,要求是一个数组 | ||
| 40 | + | ||
| 41 | + 1. text: 显示在表头的文字 | ||
| 42 | + 2. value: 对应data的key。treeTable将显示相应的value | ||
| 43 | + 3. width: 每列的宽度,为一个数字(可选) | ||
| 44 | + | ||
| 45 | + 如果你想要每个字段都有自定义的样式或者嵌套其他组件,columns可不提供,直接像在el-table一样写即可,如果没有自定义内容,提供columns将更加的便捷方便 | ||
| 46 | + | ||
| 47 | + 如果你有几个字段是需要自定义的,几个不需要,那么可以将不需要自定义的字段放入columns,将需要自定义的内容放入到slot中,详情见后文 | ||
| 48 | + ```javascript | ||
| 49 | + [{ | ||
| 50 | + value:string, | ||
| 51 | + text:string, | ||
| 52 | + width:number | ||
| 53 | + },{ | ||
| 54 | + value:string, | ||
| 55 | + text:string, | ||
| 56 | + width:number | ||
| 57 | + }] | ||
| 58 | + ``` | ||
| 59 | + | ||
| 60 | +#### expandAll | ||
| 61 | + 是否默认全部展开,boolean值,默认为false | ||
| 62 | + | ||
| 63 | +#### evalFunc | ||
| 64 | + 解析函数,function,非必须 | ||
| 65 | + | ||
| 66 | + 如果不提供,将使用默认的[evalFunc](./eval.js) | ||
| 67 | + | ||
| 68 | + 如果提供了evalFunc,那么会用提供的evalFunc去解析data,并返回treeTable渲染所需要的值。如何编写一个evalFunc,请参考[*eval.js*](https://github.com/PanJiaChen/vue-element-admin/blob/master/src/components/TreeTable/eval.js)或[*customEval.js*](https://github.com/PanJiaChen/vue-element-admin/blob/master/src/views/table/treeTable/customEval.js) | ||
| 69 | + | ||
| 70 | +#### evalArgs | ||
| 71 | + 解析函数的参数,是一个数组 | ||
| 72 | + | ||
| 73 | + **请注意,自定义的解析函数参数第一个为this.data,第二个参数为, this.expandAll,你不需要在evalArgs填写。一定记住,这两个参数是强制性的,并且位置不可颠倒** *this.data为需要解析的数据,this.expandAll为是否默认展开* | ||
| 74 | + | ||
| 75 | + 如你的解析函数需要的参数为`(this.data, this.expandAll,1,2,3,4)`,那么你只需要将`[1,2,3,4]`赋值给`evalArgs`就可以了 | ||
| 76 | + | ||
| 77 | + 如果你的解析函数参数只有`(this.data, this.expandAll)`,那么就可以不用填写evalArgs了 | ||
| 78 | + | ||
| 79 | + 具体可参考[*customEval.js*](https://github.com/PanJiaChen/vue-element-admin/blob/master/src/views/table/treeTable/customEval.js)的函数参数和[customTreeTable](https://github.com/PanJiaChen/vue-element-admin/blob/master/src/views/table/treeTable/customTreeTable.vue)的`evalArgs`属性值 | ||
| 80 | + | ||
| 81 | + ## slot | ||
| 82 | + 这是一个自定义列的插槽。 | ||
| 83 | + | ||
| 84 | + 默认情况下,treeTable只有一行行展示数据的功能。但是一般情况下,我们会要给行加上一个操作按钮或者根据当行数据展示不同的样式,这时我们就需要自定义列了。请参考[customTreeTable](https://github.com/PanJiaChen/vue-element-admin/blob/master/src/views/table/treeTable/customTreeTable.vue),[实例效果](https://panjiachen.github.io/vue-element-admin/#/table/tree-table) | ||
| 85 | + | ||
| 86 | + `slot`和`columns属性`可同时存在,columns里面的数据列会在slot自定义列的左边展示 | ||
| 87 | + | ||
| 88 | + ## 其他 | ||
| 89 | + 如果有其他的需求,请参考[el-table](http://element-cn.eleme.io/#/en-US/component/table)的api自行修改index.vue |
src/directive/clipboard/clipboard.js
0 → 100755
| 1 | +// Inspired by https://github.com/Inndy/vue-clipboard2 | ||
| 2 | +const Clipboard = require('clipboard') | ||
| 3 | +if (!Clipboard) { | ||
| 4 | + throw new Error('you should npm install `clipboard` --save at first ') | ||
| 5 | +} | ||
| 6 | + | ||
| 7 | +export default { | ||
| 8 | + bind(el, binding) { | ||
| 9 | + if (binding.arg === 'success') { | ||
| 10 | + el._v_clipboard_success = binding.value | ||
| 11 | + } else if (binding.arg === 'error') { | ||
| 12 | + el._v_clipboard_error = binding.value | ||
| 13 | + } else { | ||
| 14 | + const clipboard = new Clipboard(el, { | ||
| 15 | + text() { return binding.value }, | ||
| 16 | + action() { return binding.arg === 'cut' ? 'cut' : 'copy' } | ||
| 17 | + }) | ||
| 18 | + clipboard.on('success', e => { | ||
| 19 | + const callback = el._v_clipboard_success | ||
| 20 | + callback && callback(e) // eslint-disable-line | ||
| 21 | + }) | ||
| 22 | + clipboard.on('error', e => { | ||
| 23 | + const callback = el._v_clipboard_error | ||
| 24 | + callback && callback(e) // eslint-disable-line | ||
| 25 | + }) | ||
| 26 | + el._v_clipboard = clipboard | ||
| 27 | + } | ||
| 28 | + }, | ||
| 29 | + update(el, binding) { | ||
| 30 | + if (binding.arg === 'success') { | ||
| 31 | + el._v_clipboard_success = binding.value | ||
| 32 | + } else if (binding.arg === 'error') { | ||
| 33 | + el._v_clipboard_error = binding.value | ||
| 34 | + } else { | ||
| 35 | + el._v_clipboard.text = function() { return binding.value } | ||
| 36 | + el._v_clipboard.action = function() { return binding.arg === 'cut' ? 'cut' : 'copy' } | ||
| 37 | + } | ||
| 38 | + }, | ||
| 39 | + unbind(el, binding) { | ||
| 40 | + if (binding.arg === 'success') { | ||
| 41 | + delete el._v_clipboard_success | ||
| 42 | + } else if (binding.arg === 'error') { | ||
| 43 | + delete el._v_clipboard_error | ||
| 44 | + } else { | ||
| 45 | + el._v_clipboard.destroy() | ||
| 46 | + delete el._v_clipboard | ||
| 47 | + } | ||
| 48 | + } | ||
| 49 | +} |
src/directive/clipboard/index.js
0 → 100755
src/directive/el-dragDialog/drag.js
0 → 100755
| 1 | +export default{ | ||
| 2 | + bind(el, binding, vnode) { | ||
| 3 | + const dialogHeaderEl = el.querySelector('.el-dialog__header') | ||
| 4 | + const dragDom = el.querySelector('.el-dialog') | ||
| 5 | + dialogHeaderEl.style.cssText += ';cursor:move;' | ||
| 6 | + dragDom.style.cssText += ';top:0px;' | ||
| 7 | + | ||
| 8 | + // 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null); | ||
| 9 | + const getStyle = (function() { | ||
| 10 | + if (window.document.currentStyle) { | ||
| 11 | + return (dom, attr) => dom.currentStyle[attr] | ||
| 12 | + } else { | ||
| 13 | + return (dom, attr) => getComputedStyle(dom, false)[attr] | ||
| 14 | + } | ||
| 15 | + })() | ||
| 16 | + | ||
| 17 | + dialogHeaderEl.onmousedown = (e) => { | ||
| 18 | + // 鼠标按下,计算当前元素距离可视区的距离 | ||
| 19 | + const disX = e.clientX - dialogHeaderEl.offsetLeft | ||
| 20 | + const disY = e.clientY - dialogHeaderEl.offsetTop | ||
| 21 | + | ||
| 22 | + const dragDomWidth = dragDom.offsetWidth | ||
| 23 | + const dragDomHeight = dragDom.offsetHeight | ||
| 24 | + | ||
| 25 | + const screenWidth = document.body.clientWidth | ||
| 26 | + const screenHeight = document.body.clientHeight | ||
| 27 | + | ||
| 28 | + const minDragDomLeft = dragDom.offsetLeft | ||
| 29 | + const maxDragDomLeft = screenWidth - dragDom.offsetLeft - dragDomWidth | ||
| 30 | + | ||
| 31 | + const minDragDomTop = dragDom.offsetTop | ||
| 32 | + const maxDragDomTop = screenHeight - dragDom.offsetTop - dragDomHeight | ||
| 33 | + | ||
| 34 | + // 获取到的值带px 正则匹配替换 | ||
| 35 | + let styL = getStyle(dragDom, 'left') | ||
| 36 | + let styT = getStyle(dragDom, 'top') | ||
| 37 | + | ||
| 38 | + if (styL.includes('%')) { | ||
| 39 | + styL = +document.body.clientWidth * (+styL.replace(/\%/g, '') / 100) | ||
| 40 | + styT = +document.body.clientHeight * (+styT.replace(/\%/g, '') / 100) | ||
| 41 | + } else { | ||
| 42 | + styL = +styL.replace(/\px/g, '') | ||
| 43 | + styT = +styT.replace(/\px/g, '') | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + document.onmousemove = function(e) { | ||
| 47 | + // 通过事件委托,计算移动的距离 | ||
| 48 | + let left = e.clientX - disX | ||
| 49 | + let top = e.clientY - disY | ||
| 50 | + | ||
| 51 | + // 边界处理 | ||
| 52 | + if (-(left) > minDragDomLeft) { | ||
| 53 | + left = -minDragDomLeft | ||
| 54 | + } else if (left > maxDragDomLeft) { | ||
| 55 | + left = maxDragDomLeft | ||
| 56 | + } | ||
| 57 | + | ||
| 58 | + if (-(top) > minDragDomTop) { | ||
| 59 | + top = -minDragDomTop | ||
| 60 | + } else if (top > maxDragDomTop) { | ||
| 61 | + top = maxDragDomTop | ||
| 62 | + } | ||
| 63 | + | ||
| 64 | + // 移动当前元素 | ||
| 65 | + dragDom.style.cssText += `;left:${left + styL}px;top:${top + styT}px;` | ||
| 66 | + | ||
| 67 | + // emit onDrag event | ||
| 68 | + vnode.child.$emit('dragDialog') | ||
| 69 | + } | ||
| 70 | + | ||
| 71 | + document.onmouseup = function(e) { | ||
| 72 | + document.onmousemove = null | ||
| 73 | + document.onmouseup = null | ||
| 74 | + } | ||
| 75 | + } | ||
| 76 | + } | ||
| 77 | +} |
src/directive/el-dragDialog/index.js
0 → 100755
src/directive/permission/index.js
0 → 100755
| 1 | +import permission from './permission' | ||
| 2 | + | ||
| 3 | +const install = function(Vue) { | ||
| 4 | + Vue.directive('permission', permission) | ||
| 5 | +} | ||
| 6 | + | ||
| 7 | +if (window.Vue) { | ||
| 8 | + window['permission'] = permission | ||
| 9 | + Vue.use(install); // eslint-disable-line | ||
| 10 | +} | ||
| 11 | + | ||
| 12 | +permission.install = install | ||
| 13 | +export default permission |
src/directive/permission/permission.js
0 → 100755
| 1 | + | ||
| 2 | +import store from '@/store' | ||
| 3 | + | ||
| 4 | +export default{ | ||
| 5 | + inserted(el, binding, vnode) { | ||
| 6 | + const { value } = binding | ||
| 7 | + const roles = store.getters && store.getters.roles | ||
| 8 | + | ||
| 9 | + if (value && value instanceof Array && value.length > 0) { | ||
| 10 | + const permissionRoles = value | ||
| 11 | + | ||
| 12 | + const hasPermission = roles.some(role => { | ||
| 13 | + return permissionRoles.includes(role) | ||
| 14 | + }) | ||
| 15 | + | ||
| 16 | + if (!hasPermission) { | ||
| 17 | + el.parentNode && el.parentNode.removeChild(el) | ||
| 18 | + } | ||
| 19 | + } else { | ||
| 20 | + throw new Error(`need roles! Like v-permission="['admin','editor']"`) | ||
| 21 | + } | ||
| 22 | + } | ||
| 23 | +} |
src/directive/sticky.js
0 → 100755
| 1 | +const vueSticky = {} | ||
| 2 | +let listenAction | ||
| 3 | +vueSticky.install = Vue => { | ||
| 4 | + Vue.directive('sticky', { | ||
| 5 | + inserted(el, binding) { | ||
| 6 | + const params = binding.value || {} | ||
| 7 | + const stickyTop = params.stickyTop || 0 | ||
| 8 | + const zIndex = params.zIndex || 1000 | ||
| 9 | + const elStyle = el.style | ||
| 10 | + | ||
| 11 | + elStyle.position = '-webkit-sticky' | ||
| 12 | + elStyle.position = 'sticky' | ||
| 13 | + // if the browser support css sticky(Currently Safari, Firefox and Chrome Canary) | ||
| 14 | + // if (~elStyle.position.indexOf('sticky')) { | ||
| 15 | + // elStyle.top = `${stickyTop}px`; | ||
| 16 | + // elStyle.zIndex = zIndex; | ||
| 17 | + // return | ||
| 18 | + // } | ||
| 19 | + const elHeight = el.getBoundingClientRect().height | ||
| 20 | + const elWidth = el.getBoundingClientRect().width | ||
| 21 | + elStyle.cssText = `top: ${stickyTop}px; z-index: ${zIndex}` | ||
| 22 | + | ||
| 23 | + const parentElm = el.parentNode || document.documentElement | ||
| 24 | + const placeholder = document.createElement('div') | ||
| 25 | + placeholder.style.display = 'none' | ||
| 26 | + placeholder.style.width = `${elWidth}px` | ||
| 27 | + placeholder.style.height = `${elHeight}px` | ||
| 28 | + parentElm.insertBefore(placeholder, el) | ||
| 29 | + | ||
| 30 | + let active = false | ||
| 31 | + | ||
| 32 | + const getScroll = (target, top) => { | ||
| 33 | + const prop = top ? 'pageYOffset' : 'pageXOffset' | ||
| 34 | + const method = top ? 'scrollTop' : 'scrollLeft' | ||
| 35 | + let ret = target[prop] | ||
| 36 | + if (typeof ret !== 'number') { | ||
| 37 | + ret = window.document.documentElement[method] | ||
| 38 | + } | ||
| 39 | + return ret | ||
| 40 | + } | ||
| 41 | + | ||
| 42 | + const sticky = () => { | ||
| 43 | + if (active) { | ||
| 44 | + return | ||
| 45 | + } | ||
| 46 | + if (!elStyle.height) { | ||
| 47 | + elStyle.height = `${el.offsetHeight}px` | ||
| 48 | + } | ||
| 49 | + | ||
| 50 | + elStyle.position = 'fixed' | ||
| 51 | + elStyle.width = `${elWidth}px` | ||
| 52 | + placeholder.style.display = 'inline-block' | ||
| 53 | + active = true | ||
| 54 | + } | ||
| 55 | + | ||
| 56 | + const reset = () => { | ||
| 57 | + if (!active) { | ||
| 58 | + return | ||
| 59 | + } | ||
| 60 | + | ||
| 61 | + elStyle.position = '' | ||
| 62 | + placeholder.style.display = 'none' | ||
| 63 | + active = false | ||
| 64 | + } | ||
| 65 | + | ||
| 66 | + const check = () => { | ||
| 67 | + const scrollTop = getScroll(window, true) | ||
| 68 | + const offsetTop = el.getBoundingClientRect().top | ||
| 69 | + if (offsetTop < stickyTop) { | ||
| 70 | + sticky() | ||
| 71 | + } else { | ||
| 72 | + if (scrollTop < elHeight + stickyTop) { | ||
| 73 | + reset() | ||
| 74 | + } | ||
| 75 | + } | ||
| 76 | + } | ||
| 77 | + listenAction = () => { | ||
| 78 | + check() | ||
| 79 | + } | ||
| 80 | + | ||
| 81 | + window.addEventListener('scroll', listenAction) | ||
| 82 | + }, | ||
| 83 | + | ||
| 84 | + unbind() { | ||
| 85 | + window.removeEventListener('scroll', listenAction) | ||
| 86 | + } | ||
| 87 | + }) | ||
| 88 | +} | ||
| 89 | + | ||
| 90 | +export default vueSticky | ||
| 91 | + |
src/directive/waves/index.js
0 → 100755
src/directive/waves/waves.css
0 → 100755
| 1 | +.waves-ripple { | ||
| 2 | + position: absolute; | ||
| 3 | + border-radius: 100%; | ||
| 4 | + background-color: rgba(0, 0, 0, 0.15); | ||
| 5 | + background-clip: padding-box; | ||
| 6 | + pointer-events: none; | ||
| 7 | + -webkit-user-select: none; | ||
| 8 | + -moz-user-select: none; | ||
| 9 | + -ms-user-select: none; | ||
| 10 | + user-select: none; | ||
| 11 | + -webkit-transform: scale(0); | ||
| 12 | + -ms-transform: scale(0); | ||
| 13 | + transform: scale(0); | ||
| 14 | + opacity: 1; | ||
| 15 | +} | ||
| 16 | + | ||
| 17 | +.waves-ripple.z-active { | ||
| 18 | + opacity: 0; | ||
| 19 | + -webkit-transform: scale(2); | ||
| 20 | + -ms-transform: scale(2); | ||
| 21 | + transform: scale(2); | ||
| 22 | + -webkit-transition: opacity 1.2s ease-out, -webkit-transform 0.6s ease-out; | ||
| 23 | + transition: opacity 1.2s ease-out, -webkit-transform 0.6s ease-out; | ||
| 24 | + transition: opacity 1.2s ease-out, transform 0.6s ease-out; | ||
| 25 | + transition: opacity 1.2s ease-out, transform 0.6s ease-out, -webkit-transform 0.6s ease-out; | ||
| 26 | +} |
src/directive/waves/waves.js
0 → 100755
| 1 | +import './waves.css' | ||
| 2 | + | ||
| 3 | +export default{ | ||
| 4 | + bind(el, binding) { | ||
| 5 | + el.addEventListener('click', e => { | ||
| 6 | + const customOpts = Object.assign({}, binding.value) | ||
| 7 | + const opts = Object.assign({ | ||
| 8 | + ele: el, // 波纹作用元素 | ||
| 9 | + type: 'hit', // hit 点击位置扩散 center中心点扩展 | ||
| 10 | + color: 'rgba(0, 0, 0, 0.15)' // 波纹颜色 | ||
| 11 | + }, customOpts) | ||
| 12 | + const target = opts.ele | ||
| 13 | + if (target) { | ||
| 14 | + target.style.position = 'relative' | ||
| 15 | + target.style.overflow = 'hidden' | ||
| 16 | + const rect = target.getBoundingClientRect() | ||
| 17 | + let ripple = target.querySelector('.waves-ripple') | ||
| 18 | + if (!ripple) { | ||
| 19 | + ripple = document.createElement('span') | ||
| 20 | + ripple.className = 'waves-ripple' | ||
| 21 | + ripple.style.height = ripple.style.width = Math.max(rect.width, rect.height) + 'px' | ||
| 22 | + target.appendChild(ripple) | ||
| 23 | + } else { | ||
| 24 | + ripple.className = 'waves-ripple' | ||
| 25 | + } | ||
| 26 | + switch (opts.type) { | ||
| 27 | + case 'center': | ||
| 28 | + ripple.style.top = (rect.height / 2 - ripple.offsetHeight / 2) + 'px' | ||
| 29 | + ripple.style.left = (rect.width / 2 - ripple.offsetWidth / 2) + 'px' | ||
| 30 | + break | ||
| 31 | + default: | ||
| 32 | + ripple.style.top = (e.pageY - rect.top - ripple.offsetHeight / 2 - document.documentElement.scrollTop || document.body.scrollTop) + 'px' | ||
| 33 | + ripple.style.left = (e.pageX - rect.left - ripple.offsetWidth / 2 - document.documentElement.scrollLeft || document.body.scrollLeft) + 'px' | ||
| 34 | + } | ||
| 35 | + ripple.style.backgroundColor = opts.color | ||
| 36 | + ripple.className = 'waves-ripple z-active' | ||
| 37 | + return false | ||
| 38 | + } | ||
| 39 | + }, false) | ||
| 40 | + } | ||
| 41 | +} | ||
| 42 | + |
src/lang/en.js
0 → 100755
| 1 | +export default { | ||
| 2 | + route: { | ||
| 3 | + dashboard: 'Dashboard', | ||
| 4 | + introduction: 'Introduction', | ||
| 5 | + documentation: 'Documentation', | ||
| 6 | + guide: 'Guide', | ||
| 7 | + permission: 'Permission', | ||
| 8 | + pagePermission: 'Page Permission', | ||
| 9 | + directivePermission: 'Directive Permission', | ||
| 10 | + icons: 'Icons', | ||
| 11 | + components: 'Components', | ||
| 12 | + componentIndex: 'Introduction', | ||
| 13 | + tinymce: 'Tinymce', | ||
| 14 | + markdown: 'Markdown', | ||
| 15 | + jsonEditor: 'JSON Editor', | ||
| 16 | + dndList: 'Dnd List', | ||
| 17 | + splitPane: 'SplitPane', | ||
| 18 | + avatarUpload: 'Avatar Upload', | ||
| 19 | + dropzone: 'Dropzone', | ||
| 20 | + sticky: 'Sticky', | ||
| 21 | + countTo: 'CountTo', | ||
| 22 | + componentMixin: 'Mixin', | ||
| 23 | + backToTop: 'BackToTop', | ||
| 24 | + dragDialog: 'Drag Dialog', | ||
| 25 | + dragSelect: 'Drag Select', | ||
| 26 | + dragKanban: 'Drag Kanban', | ||
| 27 | + charts: 'Charts', | ||
| 28 | + keyboardChart: 'Keyboard Chart', | ||
| 29 | + lineChart: 'Line Chart', | ||
| 30 | + mixChart: 'Mix Chart', | ||
| 31 | + example: 'Example', | ||
| 32 | + nested: 'Nested Routes', | ||
| 33 | + menu1: 'Menu 1', | ||
| 34 | + 'menu1-1': 'Menu 1-1', | ||
| 35 | + 'menu1-2': 'Menu 1-2', | ||
| 36 | + 'menu1-2-1': 'Menu 1-2-1', | ||
| 37 | + 'menu1-2-2': 'Menu 1-2-2', | ||
| 38 | + 'menu1-3': 'Menu 1-3', | ||
| 39 | + menu2: 'Menu 2', | ||
| 40 | + Table: 'Table', | ||
| 41 | + dynamicTable: 'Dynamic Table', | ||
| 42 | + dragTable: 'Drag Table', | ||
| 43 | + inlineEditTable: 'Inline Edit', | ||
| 44 | + complexTable: 'Complex Table', | ||
| 45 | + treeTable: 'Tree Table', | ||
| 46 | + customTreeTable: 'Custom TreeTable', | ||
| 47 | + tab: 'Tab', | ||
| 48 | + form: 'Form', | ||
| 49 | + createArticle: 'Create Article', | ||
| 50 | + editArticle: 'Edit Article', | ||
| 51 | + articleList: 'Article List', | ||
| 52 | + errorPages: 'Error Pages', | ||
| 53 | + page401: '401', | ||
| 54 | + page404: '404', | ||
| 55 | + errorLog: 'Error Log', | ||
| 56 | + excel: 'Excel', | ||
| 57 | + exportExcel: 'Export Excel', | ||
| 58 | + selectExcel: 'Export Selected', | ||
| 59 | + uploadExcel: 'Upload Excel', | ||
| 60 | + zip: 'Zip', | ||
| 61 | + pdf: 'PDF', | ||
| 62 | + exportZip: 'Export Zip', | ||
| 63 | + theme: 'Theme', | ||
| 64 | + clipboardDemo: 'Clipboard', | ||
| 65 | + i18n: 'I18n', | ||
| 66 | + externalLink: 'External Link' | ||
| 67 | + }, | ||
| 68 | + navbar: { | ||
| 69 | + logOut: 'Log Out', | ||
| 70 | + dashboard: 'Dashboard', | ||
| 71 | + github: 'Github', | ||
| 72 | + theme: 'Theme', | ||
| 73 | + size: 'Global Size' | ||
| 74 | + }, | ||
| 75 | + login: { | ||
| 76 | + title: 'Login Form', | ||
| 77 | + logIn: 'Log in', | ||
| 78 | + username: 'Username', | ||
| 79 | + password: 'Password', | ||
| 80 | + any: 'any', | ||
| 81 | + thirdparty: 'Or connect with', | ||
| 82 | + thirdpartyTips: 'Can not be simulated on local, so please combine you own business simulation! ! !' | ||
| 83 | + }, | ||
| 84 | + documentation: { | ||
| 85 | + documentation: 'Documentation', | ||
| 86 | + github: 'Github Repository' | ||
| 87 | + }, | ||
| 88 | + permission: { | ||
| 89 | + roles: 'Your roles', | ||
| 90 | + switchRoles: 'Switch roles', | ||
| 91 | + tips: 'In some cases it is not suitable to use v-permission, such as element Tab component or el-table-column and other asynchronous rendering dom cases which can only be achieved by manually setting the v-if.' | ||
| 92 | + }, | ||
| 93 | + guide: { | ||
| 94 | + description: 'The guide page is useful for some people who entered the project for the first time. You can briefly introduce the features of the project. Demo is based on ', | ||
| 95 | + button: 'Show Guide' | ||
| 96 | + }, | ||
| 97 | + components: { | ||
| 98 | + documentation: 'Documentation', | ||
| 99 | + tinymceTips: 'Rich text editor is a core part of management system, but at the same time is a place with lots of problems. In the process of selecting rich texts, I also walked a lot of detours. The common rich text editors in the market are basically used, and the finally chose Tinymce. See documentation for more detailed rich text editor comparisons and introductions.', | ||
| 100 | + dropzoneTips: 'Because my business has special needs, and has to upload images to qiniu, so instead of a third party, I chose encapsulate it by myself. It is very simple, you can see the detail code in @/components/Dropzone.', | ||
| 101 | + stickyTips: 'when the page is scrolled to the preset position will be sticky on the top.', | ||
| 102 | + backToTopTips1: 'When the page is scrolled to the specified position, the Back to Top button appears in the lower right corner', | ||
| 103 | + backToTopTips2: 'You can customize the style of the button, show / hide, height of appearance, height of the return. If you need a text prompt, you can use element-ui el-tooltip elements externally', | ||
| 104 | + imageUploadTips: 'Since I was using only the vue@1 version, and it is not compatible with mockjs at the moment, I modified it myself, and if you are going to use it, it is better to use official version.' | ||
| 105 | + }, | ||
| 106 | + table: { | ||
| 107 | + dynamicTips1: 'Fixed header, sorted by header order', | ||
| 108 | + dynamicTips2: 'Not fixed header, sorted by click order', | ||
| 109 | + dragTips1: 'The default order', | ||
| 110 | + dragTips2: 'The after dragging order', | ||
| 111 | + title: 'Title', | ||
| 112 | + importance: 'Imp', | ||
| 113 | + type: 'Type', | ||
| 114 | + remark: 'Remark', | ||
| 115 | + search: 'Search', | ||
| 116 | + add: 'Add', | ||
| 117 | + export: 'Export', | ||
| 118 | + reviewer: 'reviewer', | ||
| 119 | + id: 'ID', | ||
| 120 | + date: 'Date', | ||
| 121 | + author: 'Author', | ||
| 122 | + readings: 'Readings', | ||
| 123 | + status: 'Status', | ||
| 124 | + actions: 'Actions', | ||
| 125 | + edit: 'Edit', | ||
| 126 | + publish: 'Publish', | ||
| 127 | + draft: 'Draft', | ||
| 128 | + delete: 'Delete', | ||
| 129 | + cancel: 'Cancel', | ||
| 130 | + confirm: 'Confirm' | ||
| 131 | + }, | ||
| 132 | + errorLog: { | ||
| 133 | + tips: 'Please click the bug icon in the upper right corner', | ||
| 134 | + description: 'Now the management system are basically the form of the spa, it enhances the user experience, but it also increases the possibility of page problems, a small negligence may lead to the entire page deadlock. Fortunately Vue provides a way to catch handling exceptions, where you can handle errors or report exceptions.', | ||
| 135 | + documentation: 'Document introduction' | ||
| 136 | + }, | ||
| 137 | + excel: { | ||
| 138 | + export: 'Export', | ||
| 139 | + selectedExport: 'Export Selected Items', | ||
| 140 | + placeholder: 'Please enter the file name(default excel-list)' | ||
| 141 | + }, | ||
| 142 | + zip: { | ||
| 143 | + export: 'Export', | ||
| 144 | + placeholder: 'Please enter the file name(default file)' | ||
| 145 | + }, | ||
| 146 | + pdf: { | ||
| 147 | + tips: 'Here we use window.print() to implement the feature of downloading pdf.' | ||
| 148 | + }, | ||
| 149 | + theme: { | ||
| 150 | + change: 'Change Theme', | ||
| 151 | + documentation: 'Theme documentation', | ||
| 152 | + tips: 'Tips: It is different from the theme-pick on the navbar is two different skinning methods, each with different application scenarios. Refer to the documentation for details.' | ||
| 153 | + }, | ||
| 154 | + tagsView: { | ||
| 155 | + refresh: 'Refresh', | ||
| 156 | + close: 'Close', | ||
| 157 | + closeOthers: 'Close Others', | ||
| 158 | + closeAll: 'Close All' | ||
| 159 | + } | ||
| 160 | +} |
src/lang/es.js
0 → 100755
| 1 | +export default { | ||
| 2 | + route: { | ||
| 3 | + dashboard: 'Panel de control', | ||
| 4 | + introduction: 'Introducción', | ||
| 5 | + documentation: 'Documentación', | ||
| 6 | + guide: 'Guía', | ||
| 7 | + permission: 'Permisos', | ||
| 8 | + pagePermission: 'Permisos de la página', | ||
| 9 | + directivePermission: 'Permisos de la directiva', | ||
| 10 | + icons: 'Iconos', | ||
| 11 | + components: 'Componentes', | ||
| 12 | + componentIndex: 'Introducción', | ||
| 13 | + tinymce: 'Tinymce', | ||
| 14 | + markdown: 'Markdown', | ||
| 15 | + jsonEditor: 'Editor JSON', | ||
| 16 | + dndList: 'Lista Dnd', | ||
| 17 | + splitPane: 'Panel dividido', | ||
| 18 | + avatarUpload: 'Subir avatar', | ||
| 19 | + dropzone: 'Subir ficheros', | ||
| 20 | + sticky: 'Sticky', | ||
| 21 | + countTo: 'CountTo', | ||
| 22 | + componentMixin: 'Mixin', | ||
| 23 | + backToTop: 'Ir arriba', | ||
| 24 | + dragDialog: 'Drag Dialog', | ||
| 25 | + dragSelect: 'Drag Select', | ||
| 26 | + dragKanban: 'Drag Kanban', | ||
| 27 | + charts: 'Gráficos', | ||
| 28 | + keyboardChart: 'Keyboard Chart', | ||
| 29 | + lineChart: 'Gráfico de líneas', | ||
| 30 | + mixChart: 'Mix Chart', | ||
| 31 | + example: 'Ejemplo', | ||
| 32 | + nested: 'Rutas anidadass', | ||
| 33 | + menu1: 'Menu 1', | ||
| 34 | + 'menu1-1': 'Menu 1-1', | ||
| 35 | + 'menu1-2': 'Menu 1-2', | ||
| 36 | + 'menu1-2-1': 'Menu 1-2-1', | ||
| 37 | + 'menu1-2-2': 'Menu 1-2-2', | ||
| 38 | + 'menu1-3': 'Menu 1-3', | ||
| 39 | + menu2: 'Menu 2', | ||
| 40 | + Table: 'Tabla', | ||
| 41 | + dynamicTable: 'Tabla dinámica', | ||
| 42 | + dragTable: 'Arrastrar tabla', | ||
| 43 | + inlineEditTable: 'Editor', | ||
| 44 | + complexTable: 'Complex Table', | ||
| 45 | + treeTable: 'Tree Table', | ||
| 46 | + customTreeTable: 'Custom TreeTable', | ||
| 47 | + tab: 'Pestaña', | ||
| 48 | + form: 'Formulario', | ||
| 49 | + createArticle: 'Crear artículo', | ||
| 50 | + editArticle: 'Editar artículo', | ||
| 51 | + articleList: 'Listado de artículos', | ||
| 52 | + errorPages: 'Páginas de error', | ||
| 53 | + page401: '401', | ||
| 54 | + page404: '404', | ||
| 55 | + errorLog: 'Registro de errores', | ||
| 56 | + excel: 'Excel', | ||
| 57 | + exportExcel: 'Exportar a Excel', | ||
| 58 | + selectExcel: 'Export seleccionado', | ||
| 59 | + uploadExcel: 'Subir Excel', | ||
| 60 | + zip: 'Zip', | ||
| 61 | + pdf: 'PDF', | ||
| 62 | + exportZip: 'Exportar a Zip', | ||
| 63 | + theme: 'Tema', | ||
| 64 | + clipboardDemo: 'Clipboard', | ||
| 65 | + i18n: 'I18n', | ||
| 66 | + externalLink: 'Enlace externo' | ||
| 67 | + }, | ||
| 68 | + navbar: { | ||
| 69 | + logOut: 'Salir', | ||
| 70 | + dashboard: 'Panel de control', | ||
| 71 | + github: 'Github', | ||
| 72 | + theme: 'Tema', | ||
| 73 | + size: 'Tamaño global' | ||
| 74 | + }, | ||
| 75 | + login: { | ||
| 76 | + title: 'Formulario de acceso', | ||
| 77 | + logIn: 'Acceso', | ||
| 78 | + username: 'Usuario', | ||
| 79 | + password: 'Contraseña', | ||
| 80 | + any: 'nada', | ||
| 81 | + thirdparty: 'Conectar con', | ||
| 82 | + thirdpartyTips: 'No se puede simular en local, así que combine su propia simulación de negocios. ! !' | ||
| 83 | + }, | ||
| 84 | + documentation: { | ||
| 85 | + documentation: 'Documentación', | ||
| 86 | + github: 'Repositorio Github' | ||
| 87 | + }, | ||
| 88 | + permission: { | ||
| 89 | + roles: 'Tus permisos', | ||
| 90 | + switchRoles: 'Cambiar permisos', | ||
| 91 | + tips: 'In some cases it is not suitable to use v-permission, such as element Tab component or el-table-column and other asynchronous rendering dom cases which can only be achieved by manually setting the v-if.' | ||
| 92 | + }, | ||
| 93 | + guide: { | ||
| 94 | + description: 'The guide page is useful for some people who entered the project for the first time. You can briefly introduce the features of the project. Demo is based on ', | ||
| 95 | + button: 'Ver guía' | ||
| 96 | + }, | ||
| 97 | + components: { | ||
| 98 | + documentation: 'Documentación', | ||
| 99 | + tinymceTips: 'Rich text editor is a core part of management system, but at the same time is a place with lots of problems. In the process of selecting rich texts, I also walked a lot of detours. The common rich text editors in the market are basically used, and the finally chose Tinymce. See documentation for more detailed rich text editor comparisons and introductions.', | ||
| 100 | + dropzoneTips: 'Because my business has special needs, and has to upload images to qiniu, so instead of a third party, I chose encapsulate it by myself. It is very simple, you can see the detail code in @/components/Dropzone.', | ||
| 101 | + stickyTips: 'when the page is scrolled to the preset position will be sticky on the top.', | ||
| 102 | + backToTopTips1: 'When the page is scrolled to the specified position, the Back to Top button appears in the lower right corner', | ||
| 103 | + backToTopTips2: 'You can customize the style of the button, show / hide, height of appearance, height of the return. If you need a text prompt, you can use element-ui el-tooltip elements externally', | ||
| 104 | + imageUploadTips: 'Since I was using only the vue@1 version, and it is not compatible with mockjs at the moment, I modified it myself, and if you are going to use it, it is better to use official version.' | ||
| 105 | + }, | ||
| 106 | + table: { | ||
| 107 | + dynamicTips1: 'Fixed header, sorted by header order', | ||
| 108 | + dynamicTips2: 'Not fixed header, sorted by click order', | ||
| 109 | + dragTips1: 'Orden por defecto', | ||
| 110 | + dragTips2: 'The after dragging order', | ||
| 111 | + title: 'Título', | ||
| 112 | + importance: 'Importancia', | ||
| 113 | + type: 'Tipo', | ||
| 114 | + remark: 'Remark', | ||
| 115 | + search: 'Buscar', | ||
| 116 | + add: 'Añadir', | ||
| 117 | + export: 'Exportar', | ||
| 118 | + reviewer: 'reviewer', | ||
| 119 | + id: 'ID', | ||
| 120 | + date: 'Fecha', | ||
| 121 | + author: 'Autor', | ||
| 122 | + readings: 'Lector', | ||
| 123 | + status: 'Estado', | ||
| 124 | + actions: 'Acciones', | ||
| 125 | + edit: 'Editar', | ||
| 126 | + publish: 'Publicar', | ||
| 127 | + draft: 'Draft', | ||
| 128 | + delete: 'Eliminar', | ||
| 129 | + cancel: 'Cancelar', | ||
| 130 | + confirm: 'Confirmar' | ||
| 131 | + }, | ||
| 132 | + errorLog: { | ||
| 133 | + tips: 'Please click the bug icon in the upper right corner', | ||
| 134 | + description: 'Now the management system are basically the form of the spa, it enhances the user experience, but it also increases the possibility of page problems, a small negligence may lead to the entire page deadlock. Fortunately Vue provides a way to catch handling exceptions, where you can handle errors or report exceptions.', | ||
| 135 | + documentation: 'Documento de introducción' | ||
| 136 | + }, | ||
| 137 | + excel: { | ||
| 138 | + export: 'Exportar', | ||
| 139 | + selectedExport: 'Exportar seleccionados', | ||
| 140 | + placeholder: 'Por favor escribe un nombre de fichero' | ||
| 141 | + }, | ||
| 142 | + zip: { | ||
| 143 | + export: 'Exportar', | ||
| 144 | + placeholder: 'Por favor escribe un nombre de fichero' | ||
| 145 | + }, | ||
| 146 | + pdf: { | ||
| 147 | + tips: 'Here we use window.print() to implement the feature of downloading pdf.' | ||
| 148 | + }, | ||
| 149 | + theme: { | ||
| 150 | + change: 'Cambiar tema', | ||
| 151 | + documentation: 'Documentación del tema', | ||
| 152 | + tips: 'Tips: It is different from the theme-pick on the navbar is two different skinning methods, each with different application scenarios. Refer to the documentation for details.' | ||
| 153 | + }, | ||
| 154 | + tagsView: { | ||
| 155 | + refresh: 'Actualizar', | ||
| 156 | + close: 'Cerrar', | ||
| 157 | + closeOthers: 'Cerrar otros', | ||
| 158 | + closeAll: 'Cerrar todos' | ||
| 159 | + } | ||
| 160 | +} |
src/lang/index.js
0 → 100755
| 1 | +import Vue from 'vue' | ||
| 2 | +import VueI18n from 'vue-i18n' | ||
| 3 | +import Cookies from 'js-cookie' | ||
| 4 | +import elementEnLocale from 'element-ui/lib/locale/lang/en' // element-ui lang | ||
| 5 | +import elementZhLocale from 'element-ui/lib/locale/lang/zh-CN'// element-ui lang | ||
| 6 | +import elementEsLocale from 'element-ui/lib/locale/lang/es'// element-ui lang | ||
| 7 | +import enLocale from './en' | ||
| 8 | +import zhLocale from './zh' | ||
| 9 | +import esLocale from './es' | ||
| 10 | + | ||
| 11 | +Vue.use(VueI18n) | ||
| 12 | + | ||
| 13 | +const messages = { | ||
| 14 | + en: { | ||
| 15 | + ...enLocale, | ||
| 16 | + ...elementEnLocale | ||
| 17 | + }, | ||
| 18 | + zh: { | ||
| 19 | + ...zhLocale, | ||
| 20 | + ...elementZhLocale | ||
| 21 | + }, | ||
| 22 | + es: { | ||
| 23 | + ...esLocale, | ||
| 24 | + ...elementEsLocale | ||
| 25 | + } | ||
| 26 | +} | ||
| 27 | + | ||
| 28 | +const i18n = new VueI18n({ | ||
| 29 | + // set locale | ||
| 30 | + // options: en | zh | es | ||
| 31 | + locale: Cookies.get('language') || 'en', | ||
| 32 | + // set locale messages | ||
| 33 | + messages | ||
| 34 | +}) | ||
| 35 | + | ||
| 36 | +export default i18n |
src/lang/zh.js
0 → 100755
| 1 | +export default { | ||
| 2 | + route: { | ||
| 3 | + dashboard: '首页', | ||
| 4 | + introduction: '简述', | ||
| 5 | + documentation: '文档', | ||
| 6 | + guide: '引导页', | ||
| 7 | + permission: '权限测试页', | ||
| 8 | + pagePermission: '页面权限', | ||
| 9 | + directivePermission: '指令权限', | ||
| 10 | + icons: '图标', | ||
| 11 | + components: '组件', | ||
| 12 | + componentIndex: '介绍', | ||
| 13 | + tinymce: '富文本编辑器', | ||
| 14 | + markdown: 'Markdown', | ||
| 15 | + jsonEditor: 'JSON编辑器', | ||
| 16 | + dndList: '列表拖拽', | ||
| 17 | + splitPane: 'Splitpane', | ||
| 18 | + avatarUpload: '头像上传', | ||
| 19 | + dropzone: 'Dropzone', | ||
| 20 | + sticky: 'Sticky', | ||
| 21 | + countTo: 'CountTo', | ||
| 22 | + componentMixin: '小组件', | ||
| 23 | + backToTop: '返回顶部', | ||
| 24 | + dragDialog: '拖拽 Dialog', | ||
| 25 | + dragSelect: '拖拽 Select', | ||
| 26 | + dragKanban: '可拖拽看板', | ||
| 27 | + charts: '图表', | ||
| 28 | + keyboardChart: '键盘图表', | ||
| 29 | + lineChart: '折线图', | ||
| 30 | + mixChart: '混合图表', | ||
| 31 | + example: '综合实例', | ||
| 32 | + nested: '路由嵌套', | ||
| 33 | + menu1: '菜单1', | ||
| 34 | + 'menu1-1': '菜单1-1', | ||
| 35 | + 'menu1-2': '菜单1-2', | ||
| 36 | + 'menu1-2-1': '菜单1-2-1', | ||
| 37 | + 'menu1-2-2': '菜单1-2-2', | ||
| 38 | + 'menu1-3': '菜单1-3', | ||
| 39 | + menu2: '菜单2', | ||
| 40 | + Table: 'Table', | ||
| 41 | + dynamicTable: '动态Table', | ||
| 42 | + dragTable: '拖拽Table', | ||
| 43 | + inlineEditTable: 'Table内编辑', | ||
| 44 | + complexTable: '综合Table', | ||
| 45 | + treeTable: '树形表格', | ||
| 46 | + customTreeTable: '自定义树表', | ||
| 47 | + tab: 'Tab', | ||
| 48 | + form: '表单', | ||
| 49 | + createArticle: '创建文章', | ||
| 50 | + editArticle: '编辑文章', | ||
| 51 | + articleList: '文章列表', | ||
| 52 | + errorPages: '错误页面', | ||
| 53 | + page401: '401', | ||
| 54 | + page404: '404', | ||
| 55 | + errorLog: '错误日志', | ||
| 56 | + excel: 'Excel', | ||
| 57 | + exportExcel: 'Export Excel', | ||
| 58 | + selectExcel: 'Export Selected', | ||
| 59 | + uploadExcel: 'Upload Excel', | ||
| 60 | + zip: 'Zip', | ||
| 61 | + pdf: 'PDF', | ||
| 62 | + exportZip: 'Export Zip', | ||
| 63 | + theme: '换肤', | ||
| 64 | + clipboardDemo: 'Clipboard', | ||
| 65 | + i18n: '国际化', | ||
| 66 | + externalLink: '外链' | ||
| 67 | + }, | ||
| 68 | + navbar: { | ||
| 69 | + logOut: '退出登录', | ||
| 70 | + dashboard: '首页', | ||
| 71 | + github: '项目地址', | ||
| 72 | + theme: '换肤', | ||
| 73 | + size: '布局大小' | ||
| 74 | + }, | ||
| 75 | + login: { | ||
| 76 | + title: '系统登录', | ||
| 77 | + logIn: '登录', | ||
| 78 | + username: '账号', | ||
| 79 | + password: '密码', | ||
| 80 | + any: '随便填', | ||
| 81 | + thirdparty: '第三方登录', | ||
| 82 | + thirdpartyTips: '本地不能模拟,请结合自己业务进行模拟!!!' | ||
| 83 | + }, | ||
| 84 | + documentation: { | ||
| 85 | + documentation: '文档', | ||
| 86 | + github: 'Github 地址' | ||
| 87 | + }, | ||
| 88 | + permission: { | ||
| 89 | + roles: '你的权限', | ||
| 90 | + switchRoles: '切换权限', | ||
| 91 | + tips: '在某些情况下,不适合使用 v-permission。例如:Element-UI 的 Tab 组件或 el-table-column 以及其它动态渲染 dom 的场景。你只能通过手动设置 v-if 来实现。' | ||
| 92 | + }, | ||
| 93 | + guide: { | ||
| 94 | + description: '引导页对于一些第一次进入项目的人很有用,你可以简单介绍下项目的功能。本 Demo 是基于', | ||
| 95 | + button: '打开引导' | ||
| 96 | + }, | ||
| 97 | + components: { | ||
| 98 | + documentation: '文档', | ||
| 99 | + tinymceTips: '富文本是管理后台一个核心的功能,但同时又是一个有很多坑的地方。在选择富文本的过程中我也走了不少的弯路,市面上常见的富文本都基本用过了,最终权衡了一下选择了Tinymce。更详细的富文本比较和介绍见', | ||
| 100 | + dropzoneTips: '由于我司业务有特殊需求,而且要传七牛 所以没用第三方,选择了自己封装。代码非常的简单,具体代码你可以在这里看到 @/components/Dropzone', | ||
| 101 | + stickyTips: '当页面滚动到预设的位置会吸附在顶部', | ||
| 102 | + backToTopTips1: '页面滚动到指定位置会在右下角出现返回顶部按钮', | ||
| 103 | + backToTopTips2: '可自定义按钮的样式、show/hide、出现的高度、返回的位置 如需文字提示,可在外部使用Element的el-tooltip元素', | ||
| 104 | + imageUploadTips: '由于我在使用时它只有vue@1版本,而且和mockjs不兼容,所以自己改造了一下,如果大家要使用的话,优先还是使用官方版本。' | ||
| 105 | + }, | ||
| 106 | + table: { | ||
| 107 | + dynamicTips1: '固定表头, 按照表头顺序排序', | ||
| 108 | + dynamicTips2: '不固定表头, 按照点击顺序排序', | ||
| 109 | + dragTips1: '默认顺序', | ||
| 110 | + dragTips2: '拖拽后顺序', | ||
| 111 | + title: '标题', | ||
| 112 | + importance: '重要性', | ||
| 113 | + type: '类型', | ||
| 114 | + remark: '点评', | ||
| 115 | + search: '搜索', | ||
| 116 | + add: '添加', | ||
| 117 | + export: '导出', | ||
| 118 | + reviewer: '审核人', | ||
| 119 | + id: '序号', | ||
| 120 | + date: '时间', | ||
| 121 | + author: '作者', | ||
| 122 | + readings: '阅读数', | ||
| 123 | + status: '状态', | ||
| 124 | + actions: '操作', | ||
| 125 | + edit: '编辑', | ||
| 126 | + publish: '发布', | ||
| 127 | + draft: '草稿', | ||
| 128 | + delete: '删除', | ||
| 129 | + cancel: '取 消', | ||
| 130 | + confirm: '确 定' | ||
| 131 | + }, | ||
| 132 | + errorLog: { | ||
| 133 | + tips: '请点击右上角bug小图标', | ||
| 134 | + description: '现在的管理后台基本都是spa的形式了,它增强了用户体验,但同时也会增加页面出问题的可能性,可能一个小小的疏忽就导致整个页面的死锁。好在 Vue 官网提供了一个方法来捕获处理异常,你可以在其中进行错误处理或者异常上报。', | ||
| 135 | + documentation: '文档介绍' | ||
| 136 | + }, | ||
| 137 | + excel: { | ||
| 138 | + export: '导出', | ||
| 139 | + selectedExport: '导出已选择项', | ||
| 140 | + placeholder: '请输入文件名(默认excel-list)' | ||
| 141 | + }, | ||
| 142 | + zip: { | ||
| 143 | + export: '导出', | ||
| 144 | + placeholder: '请输入文件名(默认file)' | ||
| 145 | + }, | ||
| 146 | + pdf: { | ||
| 147 | + tips: '这里使用 window.print() 来实现下载pdf的功能' | ||
| 148 | + }, | ||
| 149 | + theme: { | ||
| 150 | + change: '换肤', | ||
| 151 | + documentation: '换肤文档', | ||
| 152 | + tips: 'Tips: 它区别于 navbar 上的 theme-pick, 是两种不同的换肤方法,各自有不同的应用场景,具体请参考文档。' | ||
| 153 | + }, | ||
| 154 | + tagsView: { | ||
| 155 | + refresh: '刷新', | ||
| 156 | + close: '关闭', | ||
| 157 | + closeOthers: '关闭其它', | ||
| 158 | + closeAll: '关闭所有' | ||
| 159 | + } | ||
| 160 | +} |
| @@ -12,6 +12,7 @@ import axios from 'axios' | @@ -12,6 +12,7 @@ import axios from 'axios' | ||
| 12 | //import 'nprogress/nprogress.css' | 12 | //import 'nprogress/nprogress.css' |
| 13 | import rout from './routes' | 13 | import rout from './routes' |
| 14 | import Mock from './mock' | 14 | import Mock from './mock' |
| 15 | +import i18n from './lang' | ||
| 15 | import 'font-awesome/css/font-awesome.min.css' | 16 | import 'font-awesome/css/font-awesome.min.css' |
| 16 | 17 | ||
| 17 | //定义一个全局过滤器实现日期格式化 | 18 | //定义一个全局过滤器实现日期格式化 |
| @@ -59,18 +60,13 @@ router.beforeEach((to, from, next) => { | @@ -59,18 +60,13 @@ router.beforeEach((to, from, next) => { | ||
| 59 | } | 60 | } |
| 60 | }); | 61 | }); |
| 61 | 62 | ||
| 63 | +var message = Vue.prototype.$message; | ||
| 64 | +axios.defaults.baseURL = '/api'; | ||
| 62 | axios.interceptors.response.use( | 65 | axios.interceptors.response.use( |
| 63 | res => { | 66 | res => { |
| 64 | - //调用ELEMETN的message组件 | ||
| 65 | - let msg= Vue.prototype.$message; | ||
| 66 | - //调用route组件 | ||
| 67 | - let route = Vue.prototype.$rout; | ||
| 68 | - route.push({ | ||
| 69 | - path: "/main" | ||
| 70 | - }); | ||
| 71 | //对响应数据做些事 | 67 | //对响应数据做些事 |
| 72 | if (res.data && res.status!==200) { | 68 | if (res.data && res.status!==200) { |
| 73 | - msg({ | 69 | + message({ |
| 74 | // 饿了么的消息弹窗组件,类似toast | 70 | // 饿了么的消息弹窗组件,类似toast |
| 75 | showClose: true, | 71 | showClose: true, |
| 76 | message: 'res.data.error.message.message ? res.data.error.message.message : res.data.error.message', | 72 | message: 'res.data.error.message.message ? res.data.error.message.message : res.data.error.message', |
| @@ -82,7 +78,7 @@ axios.interceptors.response.use( | @@ -82,7 +78,7 @@ axios.interceptors.response.use( | ||
| 82 | }, | 78 | }, |
| 83 | error => { | 79 | error => { |
| 84 | // 用户登录的时候会拿到一个基础信息,比如用户名,token,过期时间戳 | 80 | // 用户登录的时候会拿到一个基础信息,比如用户名,token,过期时间戳 |
| 85 | - // 直接丢localStorage或者sessionStorage | 81 | + // 直接丢sessionStorage |
| 86 | if (!sessionStorage.getItem("token")) { | 82 | if (!sessionStorage.getItem("token")) { |
| 87 | // 若是接口访问的时候没有发现有鉴权的基础信息,直接返回登录页 | 83 | // 若是接口访问的时候没有发现有鉴权的基础信息,直接返回登录页 |
| 88 | router.push({ | 84 | router.push({ |
| @@ -92,15 +88,14 @@ axios.interceptors.response.use( | @@ -92,15 +88,14 @@ axios.interceptors.response.use( | ||
| 92 | 88 | ||
| 93 | // 下面是接口回调的satus ,因为我做了一些错误页面,所以都会指向对应的报错页面 | 89 | // 下面是接口回调的satus ,因为我做了一些错误页面,所以都会指向对应的报错页面 |
| 94 | if (error.response.status === 401) { | 90 | if (error.response.status === 401) { |
| 95 | - Vue.prototype.$message({ | ||
| 96 | - // 饿了么的消息弹窗组件,类似toast | ||
| 97 | - showClose: true, | ||
| 98 | - message: '未授权,请登录', | 91 | + router.push({ |
| 92 | + path: "/login" | ||
| 93 | + }); | ||
| 94 | + message({ | ||
| 95 | + // 饿了么的消息弹窗组件 | ||
| 96 | + message: '授权超时,或未授权,请重新登录', | ||
| 99 | type: "error" | 97 | type: "error" |
| 100 | }); | 98 | }); |
| 101 | - // router.push({ | ||
| 102 | - // path: "/login" | ||
| 103 | - // }); | ||
| 104 | } | 99 | } |
| 105 | 100 | ||
| 106 | // 下面是接口回调的satus ,因为我做了一些错误页面,所以都会指向对应的报错页面 | 101 | // 下面是接口回调的satus ,因为我做了一些错误页面,所以都会指向对应的报错页面 |
| @@ -141,6 +136,7 @@ let vue = new Vue({ | @@ -141,6 +136,7 @@ let vue = new Vue({ | ||
| 141 | //template: '<App/>', | 136 | //template: '<App/>', |
| 142 | router, | 137 | router, |
| 143 | store, | 138 | store, |
| 139 | + i18n, | ||
| 144 | //components: { App } | 140 | //components: { App } |
| 145 | render: h => h(App) | 141 | render: h => h(App) |
| 146 | }).$mount('#app') | 142 | }).$mount('#app') |
| @@ -6,6 +6,7 @@ import Main from './views/Main.vue' | @@ -6,6 +6,7 @@ import Main from './views/Main.vue' | ||
| 6 | import Role from './views/nav1/role.vue' | 6 | import Role from './views/nav1/role.vue' |
| 7 | import Perm from './views/nav1/perm.vue' | 7 | import Perm from './views/nav1/perm.vue' |
| 8 | import LOG from './views/nav1/Log.vue' | 8 | import LOG from './views/nav1/Log.vue' |
| 9 | +import PreManifest from './views/agent/PreManifest.vue' | ||
| 9 | // import Form from './views/nav1/Form.vue' | 10 | // import Form from './views/nav1/Form.vue' |
| 10 | 11 | ||
| 11 | import User from './views/nav1/user.vue' | 12 | import User from './views/nav1/user.vue' |
| @@ -51,6 +52,16 @@ let routes = [ | @@ -51,6 +52,16 @@ let routes = [ | ||
| 51 | ] | 52 | ] |
| 52 | }, | 53 | }, |
| 53 | { | 54 | { |
| 55 | + path: '/agent', | ||
| 56 | + component: Home, | ||
| 57 | + name: '代理人', | ||
| 58 | + iconCls: 'fa fa-id-card-o', | ||
| 59 | + children: [ | ||
| 60 | + { path: '/pre', component: PreManifest, name: '预配' }, | ||
| 61 | + { path: '/page5', component: Page5, name: '页面5' } | ||
| 62 | + ] | ||
| 63 | + }, | ||
| 64 | + { | ||
| 54 | path: '/', | 65 | path: '/', |
| 55 | component: Home, | 66 | component: Home, |
| 56 | name: '导航二', | 67 | name: '导航二', |
src/utils/auth.js
0 → 100755
| 1 | +import Cookies from 'js-cookie' | ||
| 2 | + | ||
| 3 | +const TokenKey = 'Admin-Token' | ||
| 4 | + | ||
| 5 | +export function getToken() { | ||
| 6 | + return Cookies.get(TokenKey) | ||
| 7 | +} | ||
| 8 | + | ||
| 9 | +export function setToken(token) { | ||
| 10 | + return Cookies.set(TokenKey, token) | ||
| 11 | +} | ||
| 12 | + | ||
| 13 | +export function removeToken() { | ||
| 14 | + return Cookies.remove(TokenKey) | ||
| 15 | +} |
src/utils/clipboard.js
0 → 100755
| 1 | +import Vue from 'vue' | ||
| 2 | +import Clipboard from 'clipboard' | ||
| 3 | + | ||
| 4 | +function clipboardSuccess() { | ||
| 5 | + Vue.prototype.$message({ | ||
| 6 | + message: 'Copy successfully', | ||
| 7 | + type: 'success', | ||
| 8 | + duration: 1500 | ||
| 9 | + }) | ||
| 10 | +} | ||
| 11 | + | ||
| 12 | +function clipboardError() { | ||
| 13 | + Vue.prototype.$message({ | ||
| 14 | + message: 'Copy failed', | ||
| 15 | + type: 'error' | ||
| 16 | + }) | ||
| 17 | +} | ||
| 18 | + | ||
| 19 | +export default function handleClipboard(text, event) { | ||
| 20 | + const clipboard = new Clipboard(event.target, { | ||
| 21 | + text: () => text | ||
| 22 | + }) | ||
| 23 | + clipboard.on('success', () => { | ||
| 24 | + clipboardSuccess() | ||
| 25 | + clipboard.off('error') | ||
| 26 | + clipboard.off('success') | ||
| 27 | + clipboard.destroy() | ||
| 28 | + }) | ||
| 29 | + clipboard.on('error', () => { | ||
| 30 | + clipboardError() | ||
| 31 | + clipboard.off('error') | ||
| 32 | + clipboard.off('success') | ||
| 33 | + clipboard.destroy() | ||
| 34 | + }) | ||
| 35 | + clipboard.onClick(event) | ||
| 36 | +} |
src/utils/companyType.js
0 → 100644
src/utils/country.js
0 → 100644
src/utils/dangerGoods.js
0 → 100644
| 1 | +const dangerGoods = [ | ||
| 2 | + { value: 'RFX', label: '禁燃物' }, | ||
| 3 | + | ||
| 4 | + { value: 'EXP', label: '快件' }, | ||
| 5 | + | ||
| 6 | + { value: 'FRO', label: '冷藏货物' }, | ||
| 7 | + | ||
| 8 | + { value: 'ELI', label: '锂电池' }, | ||
| 9 | + | ||
| 10 | + { value: 'ELM', label: '锂金属电池' }, | ||
| 11 | + | ||
| 12 | + { value: 'WET', label: '没有密水包装的湿' }, | ||
| 13 | + | ||
| 14 | + { value: 'LHO', label: '人体器官血液' }, | ||
| 15 | + | ||
| 16 | + { value: 'PEM', label: '肉类' }, | ||
| 17 | + | ||
| 18 | + { value: 'HUM', label: '尸体' }, | ||
| 19 | + | ||
| 20 | + { value: 'SPF', label: '实验动物' }, | ||
| 21 | + | ||
| 22 | + { value: 'EAT', label: '食品' }, | ||
| 23 | + | ||
| 24 | + { value: 'PEA', label: '兽皮等皮制品' }, | ||
| 25 | + | ||
| 26 | + { value: 'PEP', label: '水果蔬菜' }, | ||
| 27 | + | ||
| 28 | + { value: 'DIP', label: '外交邮袋' }, | ||
| 29 | + | ||
| 30 | + { value: 'DGR', label: '危险品' }, | ||
| 31 | + | ||
| 32 | + { value: 'PEF', label: '鲜花' }, | ||
| 33 | + | ||
| 34 | + { value: 'PER', label: '鲜活易腐物品' }, | ||
| 35 | + | ||
| 36 | + { value: 'XPS', label: '小件货物' }, | ||
| 37 | + | ||
| 38 | + { value: 'PIL', label: '药品' }, | ||
| 39 | + | ||
| 40 | + { value: 'FRI', label: '用于动植物检疫的' }, | ||
| 41 | + | ||
| 42 | + { value: 'MAL', label: '邮件' }, | ||
| 43 | + | ||
| 44 | + { value: 'ECM', label: '邮件' } | ||
| 45 | + | ||
| 46 | +] | ||
| 47 | +export default dangerGoods |
src/utils/goodsPackage.js
0 → 100644
| 1 | +const goodsPackage = [ | ||
| 2 | + { value: '1', label: '纸箱' }, | ||
| 3 | + | ||
| 4 | + { value: '2', label: '木箱' }, | ||
| 5 | + | ||
| 6 | + { value: '3', label: '桶装' }, | ||
| 7 | + | ||
| 8 | + { value: '4', label: '纸托' }, | ||
| 9 | + | ||
| 10 | + { value: '5', label: '木托' }, | ||
| 11 | + | ||
| 12 | + { value: '6', label: '塑料箱' }, | ||
| 13 | + | ||
| 14 | + { value: '7', label: '金属托' }, | ||
| 15 | + | ||
| 16 | + { value: '8', label: '散装' }, | ||
| 17 | + | ||
| 18 | + { value: '9', label: '包' }, | ||
| 19 | + | ||
| 20 | + { value: '10', label: '其他' } | ||
| 21 | +] | ||
| 22 | +export default goodsPackage |
src/utils/i18n.js
0 → 100755
| 1 | +// translate router.meta.title, be used in breadcrumb sidebar tagsview | ||
| 2 | +export function generateTitle(title) { | ||
| 3 | + const hasKey = this.$te('route.' + title) | ||
| 4 | + | ||
| 5 | + if (hasKey) { | ||
| 6 | + // $t :this method from vue-i18n, inject in @/lang/index.js | ||
| 7 | + const translatedTitle = this.$t('route.' + title) | ||
| 8 | + | ||
| 9 | + return translatedTitle | ||
| 10 | + } | ||
| 11 | + return title | ||
| 12 | +} |
src/utils/index.js
0 → 100755
| 1 | +/** | ||
| 2 | + * Created by jiachenpan on 16/11/18. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +export function parseTime(time, cFormat) { | ||
| 6 | + if (arguments.length === 0) { | ||
| 7 | + return null | ||
| 8 | + } | ||
| 9 | + const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}' | ||
| 10 | + let date | ||
| 11 | + if (typeof time === 'object') { | ||
| 12 | + date = time | ||
| 13 | + } else { | ||
| 14 | + if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) { | ||
| 15 | + time = parseInt(time) | ||
| 16 | + } | ||
| 17 | + if ((typeof time === 'number') && (time.toString().length === 10)) { | ||
| 18 | + time = time * 1000 | ||
| 19 | + } | ||
| 20 | + date = new Date(time) | ||
| 21 | + } | ||
| 22 | + const formatObj = { | ||
| 23 | + y: date.getFullYear(), | ||
| 24 | + m: date.getMonth() + 1, | ||
| 25 | + d: date.getDate(), | ||
| 26 | + h: date.getHours(), | ||
| 27 | + i: date.getMinutes(), | ||
| 28 | + s: date.getSeconds(), | ||
| 29 | + a: date.getDay() | ||
| 30 | + } | ||
| 31 | + const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => { | ||
| 32 | + let value = formatObj[key] | ||
| 33 | + // Note: getDay() returns 0 on Sunday | ||
| 34 | + if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value ] } | ||
| 35 | + if (result.length > 0 && value < 10) { | ||
| 36 | + value = '0' + value | ||
| 37 | + } | ||
| 38 | + return value || 0 | ||
| 39 | + }) | ||
| 40 | + return time_str | ||
| 41 | +} | ||
| 42 | + | ||
| 43 | +export function formatTime(time, option) { | ||
| 44 | + time = +time * 1000 | ||
| 45 | + const d = new Date(time) | ||
| 46 | + const now = Date.now() | ||
| 47 | + | ||
| 48 | + const diff = (now - d) / 1000 | ||
| 49 | + | ||
| 50 | + if (diff < 30) { | ||
| 51 | + return '刚刚' | ||
| 52 | + } else if (diff < 3600) { | ||
| 53 | + // less 1 hour | ||
| 54 | + return Math.ceil(diff / 60) + '分钟前' | ||
| 55 | + } else if (diff < 3600 * 24) { | ||
| 56 | + return Math.ceil(diff / 3600) + '小时前' | ||
| 57 | + } else if (diff < 3600 * 24 * 2) { | ||
| 58 | + return '1天前' | ||
| 59 | + } | ||
| 60 | + if (option) { | ||
| 61 | + return parseTime(time, option) | ||
| 62 | + } else { | ||
| 63 | + return ( | ||
| 64 | + d.getMonth() + | ||
| 65 | + 1 + | ||
| 66 | + '月' + | ||
| 67 | + d.getDate() + | ||
| 68 | + '日' + | ||
| 69 | + d.getHours() + | ||
| 70 | + '时' + | ||
| 71 | + d.getMinutes() + | ||
| 72 | + '分' | ||
| 73 | + ) | ||
| 74 | + } | ||
| 75 | +} | ||
| 76 | + | ||
| 77 | +// 格式化时间 | ||
| 78 | +export function getQueryObject(url) { | ||
| 79 | + url = url == null ? window.location.href : url | ||
| 80 | + const search = url.substring(url.lastIndexOf('?') + 1) | ||
| 81 | + const obj = {} | ||
| 82 | + const reg = /([^?&=]+)=([^?&=]*)/g | ||
| 83 | + search.replace(reg, (rs, $1, $2) => { | ||
| 84 | + const name = decodeURIComponent($1) | ||
| 85 | + let val = decodeURIComponent($2) | ||
| 86 | + val = String(val) | ||
| 87 | + obj[name] = val | ||
| 88 | + return rs | ||
| 89 | + }) | ||
| 90 | + return obj | ||
| 91 | +} | ||
| 92 | + | ||
| 93 | +/** | ||
| 94 | + *get getByteLen | ||
| 95 | + * @param {Sting} val input value | ||
| 96 | + * @returns {number} output value | ||
| 97 | + */ | ||
| 98 | +export function getByteLen(val) { | ||
| 99 | + let len = 0 | ||
| 100 | + for (let i = 0; i < val.length; i++) { | ||
| 101 | + if (val[i].match(/[^\x00-\xff]/gi) != null) { | ||
| 102 | + len += 1 | ||
| 103 | + } else { | ||
| 104 | + len += 0.5 | ||
| 105 | + } | ||
| 106 | + } | ||
| 107 | + return Math.floor(len) | ||
| 108 | +} | ||
| 109 | + | ||
| 110 | +export function cleanArray(actual) { | ||
| 111 | + const newArray = [] | ||
| 112 | + for (let i = 0; i < actual.length; i++) { | ||
| 113 | + if (actual[i]) { | ||
| 114 | + newArray.push(actual[i]) | ||
| 115 | + } | ||
| 116 | + } | ||
| 117 | + return newArray | ||
| 118 | +} | ||
| 119 | + | ||
| 120 | +export function param(json) { | ||
| 121 | + if (!json) return '' | ||
| 122 | + return cleanArray( | ||
| 123 | + Object.keys(json).map(key => { | ||
| 124 | + if (json[key] === undefined) return '' | ||
| 125 | + return encodeURIComponent(key) + '=' + encodeURIComponent(json[key]) | ||
| 126 | + }) | ||
| 127 | + ).join('&') | ||
| 128 | +} | ||
| 129 | + | ||
| 130 | +export function param2Obj(url) { | ||
| 131 | + const search = url.split('?')[1] | ||
| 132 | + if (!search) { | ||
| 133 | + return {} | ||
| 134 | + } | ||
| 135 | + return JSON.parse( | ||
| 136 | + '{"' + | ||
| 137 | + decodeURIComponent(search) | ||
| 138 | + .replace(/"/g, '\\"') | ||
| 139 | + .replace(/&/g, '","') | ||
| 140 | + .replace(/=/g, '":"') + | ||
| 141 | + '"}' | ||
| 142 | + ) | ||
| 143 | +} | ||
| 144 | + | ||
| 145 | +export function html2Text(val) { | ||
| 146 | + const div = document.createElement('div') | ||
| 147 | + div.innerHTML = val | ||
| 148 | + return div.textContent || div.innerText | ||
| 149 | +} | ||
| 150 | + | ||
| 151 | +export function objectMerge(target, source) { | ||
| 152 | + /* Merges two objects, | ||
| 153 | + giving the last one precedence */ | ||
| 154 | + | ||
| 155 | + if (typeof target !== 'object') { | ||
| 156 | + target = {} | ||
| 157 | + } | ||
| 158 | + if (Array.isArray(source)) { | ||
| 159 | + return source.slice() | ||
| 160 | + } | ||
| 161 | + Object.keys(source).forEach(property => { | ||
| 162 | + const sourceProperty = source[property] | ||
| 163 | + if (typeof sourceProperty === 'object') { | ||
| 164 | + target[property] = objectMerge(target[property], sourceProperty) | ||
| 165 | + } else { | ||
| 166 | + target[property] = sourceProperty | ||
| 167 | + } | ||
| 168 | + }) | ||
| 169 | + return target | ||
| 170 | +} | ||
| 171 | + | ||
| 172 | +export function toggleClass(element, className) { | ||
| 173 | + if (!element || !className) { | ||
| 174 | + return | ||
| 175 | + } | ||
| 176 | + let classString = element.className | ||
| 177 | + const nameIndex = classString.indexOf(className) | ||
| 178 | + if (nameIndex === -1) { | ||
| 179 | + classString += '' + className | ||
| 180 | + } else { | ||
| 181 | + classString = | ||
| 182 | + classString.substr(0, nameIndex) + | ||
| 183 | + classString.substr(nameIndex + className.length) | ||
| 184 | + } | ||
| 185 | + element.className = classString | ||
| 186 | +} | ||
| 187 | + | ||
| 188 | +export const pickerOptions = [ | ||
| 189 | + { | ||
| 190 | + text: '今天', | ||
| 191 | + onClick(picker) { | ||
| 192 | + const end = new Date() | ||
| 193 | + const start = new Date(new Date().toDateString()) | ||
| 194 | + end.setTime(start.getTime()) | ||
| 195 | + picker.$emit('pick', [start, end]) | ||
| 196 | + } | ||
| 197 | + }, | ||
| 198 | + { | ||
| 199 | + text: '最近一周', | ||
| 200 | + onClick(picker) { | ||
| 201 | + const end = new Date(new Date().toDateString()) | ||
| 202 | + const start = new Date() | ||
| 203 | + start.setTime(end.getTime() - 3600 * 1000 * 24 * 7) | ||
| 204 | + picker.$emit('pick', [start, end]) | ||
| 205 | + } | ||
| 206 | + }, | ||
| 207 | + { | ||
| 208 | + text: '最近一个月', | ||
| 209 | + onClick(picker) { | ||
| 210 | + const end = new Date(new Date().toDateString()) | ||
| 211 | + const start = new Date() | ||
| 212 | + start.setTime(start.getTime() - 3600 * 1000 * 24 * 30) | ||
| 213 | + picker.$emit('pick', [start, end]) | ||
| 214 | + } | ||
| 215 | + }, | ||
| 216 | + { | ||
| 217 | + text: '最近三个月', | ||
| 218 | + onClick(picker) { | ||
| 219 | + const end = new Date(new Date().toDateString()) | ||
| 220 | + const start = new Date() | ||
| 221 | + start.setTime(start.getTime() - 3600 * 1000 * 24 * 90) | ||
| 222 | + picker.$emit('pick', [start, end]) | ||
| 223 | + } | ||
| 224 | + } | ||
| 225 | +] | ||
| 226 | + | ||
| 227 | +export function getTime(type) { | ||
| 228 | + if (type === 'start') { | ||
| 229 | + return new Date().getTime() - 3600 * 1000 * 24 * 90 | ||
| 230 | + } else { | ||
| 231 | + return new Date(new Date().toDateString()) | ||
| 232 | + } | ||
| 233 | +} | ||
| 234 | + | ||
| 235 | +export function debounce(func, wait, immediate) { | ||
| 236 | + let timeout, args, context, timestamp, result | ||
| 237 | + | ||
| 238 | + const later = function() { | ||
| 239 | + // 据上一次触发时间间隔 | ||
| 240 | + const last = +new Date() - timestamp | ||
| 241 | + | ||
| 242 | + // 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait | ||
| 243 | + if (last < wait && last > 0) { | ||
| 244 | + timeout = setTimeout(later, wait - last) | ||
| 245 | + } else { | ||
| 246 | + timeout = null | ||
| 247 | + // 如果设定为immediate===true,因为开始边界已经调用过了此处无需调用 | ||
| 248 | + if (!immediate) { | ||
| 249 | + result = func.apply(context, args) | ||
| 250 | + if (!timeout) context = args = null | ||
| 251 | + } | ||
| 252 | + } | ||
| 253 | + } | ||
| 254 | + | ||
| 255 | + return function(...args) { | ||
| 256 | + context = this | ||
| 257 | + timestamp = +new Date() | ||
| 258 | + const callNow = immediate && !timeout | ||
| 259 | + // 如果延时不存在,重新设定延时 | ||
| 260 | + if (!timeout) timeout = setTimeout(later, wait) | ||
| 261 | + if (callNow) { | ||
| 262 | + result = func.apply(context, args) | ||
| 263 | + context = args = null | ||
| 264 | + } | ||
| 265 | + | ||
| 266 | + return result | ||
| 267 | + } | ||
| 268 | +} | ||
| 269 | + | ||
| 270 | +/** | ||
| 271 | + * This is just a simple version of deep copy | ||
| 272 | + * Has a lot of edge cases bug | ||
| 273 | + * If you want to use a perfect deep copy, use lodash's _.cloneDeep | ||
| 274 | + */ | ||
| 275 | +export function deepClone(source) { | ||
| 276 | + if (!source && typeof source !== 'object') { | ||
| 277 | + throw new Error('error arguments', 'shallowClone') | ||
| 278 | + } | ||
| 279 | + const targetObj = source.constructor === Array ? [] : {} | ||
| 280 | + Object.keys(source).forEach(keys => { | ||
| 281 | + if (source[keys] && typeof source[keys] === 'object') { | ||
| 282 | + targetObj[keys] = deepClone(source[keys]) | ||
| 283 | + } else { | ||
| 284 | + targetObj[keys] = source[keys] | ||
| 285 | + } | ||
| 286 | + }) | ||
| 287 | + return targetObj | ||
| 288 | +} | ||
| 289 | + | ||
| 290 | +export function uniqueArr(arr) { | ||
| 291 | + return Array.from(new Set(arr)) | ||
| 292 | +} | ||
| 293 | + | ||
| 294 | +export function createUniqueString() { | ||
| 295 | + const timestamp = +new Date() + '' | ||
| 296 | + const randomNum = parseInt((1 + Math.random()) * 65536) + '' | ||
| 297 | + return (+(randomNum + timestamp)).toString(32) | ||
| 298 | +} |
src/utils/openWindow.js
0 → 100755
| 1 | +/** | ||
| 2 | + *Created by jiachenpan on 16/11/29. | ||
| 3 | + * @param {Sting} url | ||
| 4 | + * @param {Sting} title | ||
| 5 | + * @param {Number} w | ||
| 6 | + * @param {Number} h | ||
| 7 | + */ | ||
| 8 | + | ||
| 9 | +export default function openWindow(url, title, w, h) { | ||
| 10 | + // Fixes dual-screen position Most browsers Firefox | ||
| 11 | + const dualScreenLeft = window.screenLeft !== undefined ? window.screenLeft : screen.left | ||
| 12 | + const dualScreenTop = window.screenTop !== undefined ? window.screenTop : screen.top | ||
| 13 | + | ||
| 14 | + const width = window.innerWidth ? window.innerWidth : document.documentElement.clientWidth ? document.documentElement.clientWidth : screen.width | ||
| 15 | + const height = window.innerHeight ? window.innerHeight : document.documentElement.clientHeight ? document.documentElement.clientHeight : screen.height | ||
| 16 | + | ||
| 17 | + const left = ((width / 2) - (w / 2)) + dualScreenLeft | ||
| 18 | + const top = ((height / 2) - (h / 2)) + dualScreenTop | ||
| 19 | + const newWindow = window.open(url, title, 'toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, resizable=yes, copyhistory=no, width=' + w + ', height=' + h + ', top=' + top + ', left=' + left) | ||
| 20 | + | ||
| 21 | + // Puts focus on the newWindow | ||
| 22 | + if (window.focus) { | ||
| 23 | + newWindow.focus() | ||
| 24 | + } | ||
| 25 | +} | ||
| 26 | + |
src/utils/permission.js
0 → 100755
| 1 | +import store from '@/store' | ||
| 2 | + | ||
| 3 | +/** | ||
| 4 | + * @param {Array} value | ||
| 5 | + * @returns {Boolean} | ||
| 6 | + * @example see @/views/permission/directive.vue | ||
| 7 | + */ | ||
| 8 | +export default function checkPermission(value) { | ||
| 9 | + if (value && value instanceof Array && value.length > 0) { | ||
| 10 | + const roles = store.getters && store.getters.roles | ||
| 11 | + const permissionRoles = value | ||
| 12 | + | ||
| 13 | + const hasPermission = roles.some(role => { | ||
| 14 | + return permissionRoles.includes(role) | ||
| 15 | + }) | ||
| 16 | + | ||
| 17 | + if (!hasPermission) { | ||
| 18 | + return false | ||
| 19 | + } | ||
| 20 | + return true | ||
| 21 | + } else { | ||
| 22 | + console.error(`need roles! Like v-permission="['admin','editor']"`) | ||
| 23 | + return false | ||
| 24 | + } | ||
| 25 | +} |
src/utils/request.js
0 → 100755
| 1 | +import axios from 'axios' | ||
| 2 | +import { Message } from 'element-ui' | ||
| 3 | +import store from '@/store' | ||
| 4 | +import { getToken } from '@/utils/auth' | ||
| 5 | + | ||
| 6 | +// create an axios instance | ||
| 7 | +const service = axios.create({ | ||
| 8 | + baseURL: process.env.BASE_API, // api 的 base_url | ||
| 9 | + timeout: 5000 // request timeout | ||
| 10 | +}) | ||
| 11 | + | ||
| 12 | +// request interceptor | ||
| 13 | +service.interceptors.request.use( | ||
| 14 | + config => { | ||
| 15 | + // Do something before request is sent | ||
| 16 | + if (store.getters.token) { | ||
| 17 | + // 让每个请求携带token-- ['X-Token']为自定义key 请根据实际情况自行修改 | ||
| 18 | + config.headers['X-Token'] = getToken() | ||
| 19 | + } | ||
| 20 | + return config | ||
| 21 | + }, | ||
| 22 | + error => { | ||
| 23 | + // Do something with request error | ||
| 24 | + console.log(error) // for debug | ||
| 25 | + Promise.reject(error) | ||
| 26 | + } | ||
| 27 | +) | ||
| 28 | + | ||
| 29 | +// response interceptor | ||
| 30 | +service.interceptors.response.use( | ||
| 31 | + response => response, | ||
| 32 | + /** | ||
| 33 | + * 下面的注释为通过在response里,自定义code来标示请求状态 | ||
| 34 | + * 当code返回如下情况则说明权限有问题,登出并返回到登录页 | ||
| 35 | + * 如想通过 xmlhttprequest 来状态码标识 逻辑可写在下面error中 | ||
| 36 | + * 以下代码均为样例,请结合自生需求加以修改,若不需要,则可删除 | ||
| 37 | + */ | ||
| 38 | + // response => { | ||
| 39 | + // const res = response.data | ||
| 40 | + // if (res.code !== 20000) { | ||
| 41 | + // Message({ | ||
| 42 | + // message: res.message, | ||
| 43 | + // type: 'error', | ||
| 44 | + // duration: 5 * 1000 | ||
| 45 | + // }) | ||
| 46 | + // // 50008:非法的token; 50012:其他客户端登录了; 50014:Token 过期了; | ||
| 47 | + // if (res.code === 50008 || res.code === 50012 || res.code === 50014) { | ||
| 48 | + // // 请自行在引入 MessageBox | ||
| 49 | + // // import { Message, MessageBox } from 'element-ui' | ||
| 50 | + // MessageBox.confirm('你已被登出,可以取消继续留在该页面,或者重新登录', '确定登出', { | ||
| 51 | + // confirmButtonText: '重新登录', | ||
| 52 | + // cancelButtonText: '取消', | ||
| 53 | + // type: 'warning' | ||
| 54 | + // }).then(() => { | ||
| 55 | + // store.dispatch('FedLogOut').then(() => { | ||
| 56 | + // location.reload() // 为了重新实例化vue-router对象 避免bug | ||
| 57 | + // }) | ||
| 58 | + // }) | ||
| 59 | + // } | ||
| 60 | + // return Promise.reject('error') | ||
| 61 | + // } else { | ||
| 62 | + // return response.data | ||
| 63 | + // } | ||
| 64 | + // }, | ||
| 65 | + error => { | ||
| 66 | + console.log('err' + error) // for debug | ||
| 67 | + Message({ | ||
| 68 | + message: error.message, | ||
| 69 | + type: 'error', | ||
| 70 | + duration: 5 * 1000 | ||
| 71 | + }) | ||
| 72 | + return Promise.reject(error) | ||
| 73 | + } | ||
| 74 | +) | ||
| 75 | + | ||
| 76 | +export default service |
src/utils/scrollTo.js
0 → 100755
| 1 | +Math.easeInOutQuad = function(t, b, c, d) { | ||
| 2 | + t /= d / 2 | ||
| 3 | + if (t < 1) { | ||
| 4 | + return c / 2 * t * t + b | ||
| 5 | + } | ||
| 6 | + t-- | ||
| 7 | + return -c / 2 * (t * (t - 2) - 1) + b | ||
| 8 | +} | ||
| 9 | + | ||
| 10 | +// requestAnimationFrame for Smart Animating http://goo.gl/sx5sts | ||
| 11 | +var requestAnimFrame = (function() { | ||
| 12 | + return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function(callback) { window.setTimeout(callback, 1000 / 60) } | ||
| 13 | +})() | ||
| 14 | + | ||
| 15 | +// because it's so fucking difficult to detect the scrolling element, just move them all | ||
| 16 | +function move(amount) { | ||
| 17 | + document.documentElement.scrollTop = amount | ||
| 18 | + document.body.parentNode.scrollTop = amount | ||
| 19 | + document.body.scrollTop = amount | ||
| 20 | +} | ||
| 21 | + | ||
| 22 | +function position() { | ||
| 23 | + return document.documentElement.scrollTop || document.body.parentNode.scrollTop || document.body.scrollTop | ||
| 24 | +} | ||
| 25 | + | ||
| 26 | +export function scrollTo(to, duration, callback) { | ||
| 27 | + const start = position() | ||
| 28 | + const change = to - start | ||
| 29 | + const increment = 20 | ||
| 30 | + let currentTime = 0 | ||
| 31 | + duration = (typeof (duration) === 'undefined') ? 500 : duration | ||
| 32 | + var animateScroll = function() { | ||
| 33 | + // increment the time | ||
| 34 | + currentTime += increment | ||
| 35 | + // find the value with the quadratic in-out easing function | ||
| 36 | + var val = Math.easeInOutQuad(currentTime, start, change, duration) | ||
| 37 | + // move the document.body | ||
| 38 | + move(val) | ||
| 39 | + // do the animation unless its over | ||
| 40 | + if (currentTime < duration) { | ||
| 41 | + requestAnimFrame(animateScroll) | ||
| 42 | + } else { | ||
| 43 | + if (callback && typeof (callback) === 'function') { | ||
| 44 | + // the animation is done so lets callback | ||
| 45 | + callback() | ||
| 46 | + } | ||
| 47 | + } | ||
| 48 | + } | ||
| 49 | + animateScroll() | ||
| 50 | +} |
src/utils/uld.js
0 → 100644
src/utils/validate.js
0 → 100755
| 1 | +/** | ||
| 2 | + * Created by jiachenpan on 16/11/18. | ||
| 3 | + */ | ||
| 4 | + | ||
| 5 | +export function isExternal(path) { | ||
| 6 | + return /^(https?:|mailto:|tel:)/.test(path) | ||
| 7 | +} | ||
| 8 | + | ||
| 9 | +export function validUsername(str) { | ||
| 10 | + const valid_map = ['admin', 'editor'] | ||
| 11 | + return valid_map.indexOf(str.trim()) >= 0 | ||
| 12 | +} | ||
| 13 | + | ||
| 14 | +/* 合法uri*/ | ||
| 15 | +export function validURL(url) { | ||
| 16 | + const reg = /^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/ | ||
| 17 | + return reg.test(url) | ||
| 18 | +} | ||
| 19 | + | ||
| 20 | +/* 小写字母*/ | ||
| 21 | +export function validLowerCase(str) { | ||
| 22 | + const reg = /^[a-z]+$/ | ||
| 23 | + return reg.test(str) | ||
| 24 | +} | ||
| 25 | + | ||
| 26 | +/* 大写字母*/ | ||
| 27 | +export function validUpperCase(str) { | ||
| 28 | + const reg = /^[A-Z]+$/ | ||
| 29 | + return reg.test(str) | ||
| 30 | +} | ||
| 31 | + | ||
| 32 | +/* 大小写字母*/ | ||
| 33 | +export function validAlphabets(str) { | ||
| 34 | + const reg = /^[A-Za-z]+$/ | ||
| 35 | + return reg.test(str) | ||
| 36 | +} | ||
| 37 | + | ||
| 38 | +/** | ||
| 39 | + * validate email | ||
| 40 | + * @param email | ||
| 41 | + * @returns {boolean} | ||
| 42 | + */ | ||
| 43 | +export function validEmail(email) { | ||
| 44 | + const re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ | ||
| 45 | + return re.test(email) | ||
| 46 | +} |
src/views/agent/PreManifest.vue
0 → 100755
| 1 | +<template> | ||
| 2 | + <div class="app-container"> | ||
| 3 | + <div class="filter-container"> | ||
| 4 | + <el-input v-model="listQuery.title" style="width: 200px;" class="filter-item" placeholder="运单号"/> | ||
| 5 | + <el-input v-model="listQuery.title" style="width: 200px;" class="filter-item" placeholder="航班号"/> | ||
| 6 | + <el-input v-model="listQuery.title" style="width: 200px;" class="filter-item" placeholder="航班日期"/> | ||
| 7 | + <el-button v-waves class="filter-item" type="primary" icon="el-icon-search" @click="handleFilter">{{ $t('table.search') }}</el-button> | ||
| 8 | + <el-button class="filter-item" style="margin-left: 10px;" type="primary" icon="el-icon-edit" @click="handleCreate">{{ $t('table.add') }}</el-button> | ||
| 9 | + <el-button v-waves :loading="downloadLoading" class="filter-item" type="primary" icon="el-icon-download" @click="handleDownload">{{ $t('table.export') }}</el-button> | ||
| 10 | + <el-button class="filter-item" style="margin-left: 10px;" type="primary" icon="el-icon-message" @click="handleCreate">批量发送</el-button> | ||
| 11 | + </div> | ||
| 12 | + <tree-table :data="data" :eval-func="func" :eval-args="args" :expand-all="expandAll" stripe="true" style="font-size: 13px" border @selection-change="handleSelectionChange"> | ||
| 13 | + <el-table-column prop="waybillNo" label="主单号" width="110px" align="center" sortable> | ||
| 14 | + <template slot-scope="scope"> | ||
| 15 | + <span>{{ scope.row.waybillNo }}</span> | ||
| 16 | + </template> | ||
| 17 | + </el-table-column> | ||
| 18 | + <el-table-column label="分单号" width="120px" align="center" sortable> | ||
| 19 | + <template slot-scope="scope"> | ||
| 20 | + <span>{{ scope.row.houseWaybillNo }}</span> | ||
| 21 | + </template> | ||
| 22 | + </el-table-column> | ||
| 23 | + <el-table-column label="航班号" width="90px" align="center" sortable> | ||
| 24 | + <template slot-scope="scope"> | ||
| 25 | + <span>{{ scope.row.flight }}</span> | ||
| 26 | + </template> | ||
| 27 | + </el-table-column> | ||
| 28 | + <el-table-column label="航班日期" width="100px" align="center" sortable> | ||
| 29 | + <template slot-scope="scope"> | ||
| 30 | + <span>{{ scope.row.flightDate | parseTime('{y}-{m}-{d}') }}</span> | ||
| 31 | + </template> | ||
| 32 | + </el-table-column> | ||
| 33 | + <el-table-column label="起始站" width="60px" align="center"> | ||
| 34 | + <template slot-scope="scope"> | ||
| 35 | + <span>{{ scope.row.oriStation }}</span> | ||
| 36 | + </template> | ||
| 37 | + </el-table-column> | ||
| 38 | + <el-table-column label="目的站" width="60px" align="center"> | ||
| 39 | + <template slot-scope="scope"> | ||
| 40 | + <span>{{ scope.row.desStation }}</span> | ||
| 41 | + </template> | ||
| 42 | + </el-table-column> | ||
| 43 | + <el-table-column label="预配件数" width="80px" align="center"> | ||
| 44 | + <template slot-scope="scope"> | ||
| 45 | + <span>{{ scope.row.maniPiece }}</span> | ||
| 46 | + </template> | ||
| 47 | + </el-table-column> | ||
| 48 | + <el-table-column label="预配重量" width="80px" align="center"> | ||
| 49 | + <template slot-scope="scope"> | ||
| 50 | + <span>{{ scope.row.maniWeight }}</span> | ||
| 51 | + </template> | ||
| 52 | + </el-table-column> | ||
| 53 | + <el-table-column :label="$t('table.status')" class-name="status-col" width="90" sortable> | ||
| 54 | + <template slot-scope="scope"> | ||
| 55 | + <el-tag :type="scope.row.status | statusFilter">{{ scope.row.status }}</el-tag> | ||
| 56 | + </template> | ||
| 57 | + </el-table-column> | ||
| 58 | + <el-table-column label="回执内容" width="230px" align="center"> | ||
| 59 | + <template slot-scope="scope"> | ||
| 60 | + <span>{{ scope.row.customText }}</span> | ||
| 61 | + <div> | ||
| 62 | + <el-progress :percentage="scope.row.customComplate" :status="scope.row.status | statusFilter" /> | ||
| 63 | + </div> | ||
| 64 | + </template> | ||
| 65 | + </el-table-column> | ||
| 66 | + <el-table-column :label="$t('table.actions')" align="center" class-name="small-padding fixed-width"> | ||
| 67 | + <template slot-scope="scope"> | ||
| 68 | + <el-button type="primary" size="small" @click="handleUpdate(scope.row)">快速编辑</el-button> | ||
| 69 | + <el-button type="primary" size="mini" @click="handleUpdate(scope.row)">{{ $t('table.edit') }}</el-button> | ||
| 70 | + <el-button v-if="scope.row.status!='41301'" size="mini" type="success" @click="handleModifyStatus(scope.row,'41301')">{{ $t('table.publish') }}</el-button> | ||
| 71 | + <el-button v-if="scope.row.status!='10002'" size="small" @click="handleModifyStatus(scope.row,'10002')">客服反馈</el-button> | ||
| 72 | + <el-button v-if="scope.row.status=='10002'" size="mini" type="danger" @click="handleModifyStatus(scope.row,'deleted')">{{ $t('table.delete') }}</el-button> | ||
| 73 | + <el-switch | ||
| 74 | + v-model="resend" | ||
| 75 | + active-color="#13ce66" | ||
| 76 | + inactive-color="#ff4949" /> | ||
| 77 | + </template> | ||
| 78 | + </el-table-column> | ||
| 79 | + </tree-table> | ||
| 80 | + <pagination v-show="total>0" :total="total" :page.sync="listQuery.page" :limit.sync="listQuery.limit" @pagination="getList" /> | ||
| 81 | + | ||
| 82 | + <el-dialog :title="textMap[dialogStatus]" :visible.sync="dialogFormVisible" fullscreen="true"> | ||
| 83 | + <el-form ref="" :inline="true" :label-position="left" :rules="rules" :model="temp" label-width="100px" style="font-size: 13px"> | ||
| 84 | + <div> | ||
| 85 | + <el-tag type="info" effect="plain"> | ||
| 86 | + 航班信息 | ||
| 87 | + </el-tag> | ||
| 88 | + </div> | ||
| 89 | + <el-row type="flex" class="row-bg bg-purple"> | ||
| 90 | + <el-col :span="24"> | ||
| 91 | + <div class="grid-content"> | ||
| 92 | + <el-form-item label="航班号" prop="flight"> | ||
| 93 | + <el-input v-model="temp.flight"/> | ||
| 94 | + </el-form-item> | ||
| 95 | + <el-form-item label="航班日期" prop="flightDate"> | ||
| 96 | + <el-date-picker :picker-options="pickerOptions" v-model="temp.flightDate" align="right" type="date" placeholder="请输入航班日期" /> | ||
| 97 | + </el-form-item> | ||
| 98 | + </div> | ||
| 99 | + </el-col> | ||
| 100 | + </el-row> | ||
| 101 | + <div> | ||
| 102 | + <el-tag type="info" effect="plain"> | ||
| 103 | + 运单信息 | ||
| 104 | + </el-tag> | ||
| 105 | + </div> | ||
| 106 | + <el-form-item label="主单号" prop="waybillNo"> | ||
| 107 | + <el-input v-model="temp.waybillNo"/> | ||
| 108 | + </el-form-item> | ||
| 109 | + <el-form-item label="分单号" prop="houseWaybillNo"> | ||
| 110 | + <el-input v-model="temp.houseWaybillNo"/> | ||
| 111 | + </el-form-item> | ||
| 112 | + <el-form-item label="关区代码" prop="custom"> | ||
| 113 | + <el-select v-model="temp.custom" class="filter-item" placeholder="请选择关区代码"> | ||
| 114 | + <el-option v-for="item in manifestCustoms" :key="item" :label="item" :value="item"/> | ||
| 115 | + </el-select> | ||
| 116 | + </el-form-item> | ||
| 117 | + <el-form-item label="起始站" prop="oriStation"> | ||
| 118 | + <el-input v-model="temp.oriStation"/> | ||
| 119 | + </el-form-item> | ||
| 120 | + <el-form-item label="目的站" prop="desStation"> | ||
| 121 | + <el-input v-model="temp.desStation"/> | ||
| 122 | + </el-form-item> | ||
| 123 | + <el-form-item label="预配件数" prop="maniPiece"> | ||
| 124 | + <el-input v-model.number="temp.maniPiece"/> | ||
| 125 | + </el-form-item> | ||
| 126 | + <el-form-item label="预配重量" prop="maniWeight"> | ||
| 127 | + <el-input v-model.number="temp.maniWeight"/> | ||
| 128 | + </el-form-item> | ||
| 129 | + <el-form-item label="付费方式" prop="payMode"> | ||
| 130 | + <el-select v-model="temp.payMode" class="filter-item" placeholder="付费方式"> | ||
| 131 | + <el-option v-for="item in manifestCustoms" :key="item" :label="item" :value="item"/> | ||
| 132 | + </el-select> | ||
| 133 | + </el-form-item> | ||
| 134 | + <el-form-item label="海关状态" prop="goodsType"> | ||
| 135 | + <el-select v-model="temp.goodsType" class="filter-item" placeholder="请录入货物类型"> | ||
| 136 | + <el-option v-for="item in manifestCustoms" :key="item" :label="item" :value="item"/> | ||
| 137 | + </el-select> | ||
| 138 | + </el-form-item> | ||
| 139 | + <div> | ||
| 140 | + <el-tag type="info" effect="plain"> | ||
| 141 | + 发货人信息 | ||
| 142 | + </el-tag> | ||
| 143 | + </div> | ||
| 144 | + <el-row type="flex" class="row-bg bg-purple"> | ||
| 145 | + <el-col :span="24"> | ||
| 146 | + <div class="grid-content"> | ||
| 147 | + <el-form-item label="公司" prop="shpCompany"> | ||
| 148 | + <el-input v-model="temp.shpCompany"/> | ||
| 149 | + </el-form-item> | ||
| 150 | + <el-form-item label="地址" prop="shpAddress"> | ||
| 151 | + <el-input v-model="temp.shpAddress"/> | ||
| 152 | + </el-form-item> | ||
| 153 | + <el-form-item label="城市" prop="shpCity"> | ||
| 154 | + <el-input v-model="temp.shpAddress"/> | ||
| 155 | + </el-form-item> | ||
| 156 | + <el-form-item label="邮编" prop="shpCity"> | ||
| 157 | + <el-input v-model="temp.shpAddress"/> | ||
| 158 | + </el-form-item> | ||
| 159 | + <el-form-item label="电话" prop="shpCity"> | ||
| 160 | + <el-input v-model="temp.shpAddress"/> | ||
| 161 | + </el-form-item> | ||
| 162 | + <el-form-item label="传真" prop="shpCity"> | ||
| 163 | + <el-input v-model="temp.shpAddress"/> | ||
| 164 | + </el-form-item> | ||
| 165 | + </div> | ||
| 166 | + <div> | ||
| 167 | + <el-form-item label="国家" prop="shpCountry"> | ||
| 168 | + <el-select | ||
| 169 | + :remote-method="remoteMethod" | ||
| 170 | + :loading="loading" | ||
| 171 | + v-model="temp.country" | ||
| 172 | + filterable | ||
| 173 | + remote | ||
| 174 | + placeholder="请选择" > | ||
| 175 | + <el-option | ||
| 176 | + v-for="item in countryOption" | ||
| 177 | + :key="item.value" | ||
| 178 | + :label="item.label" | ||
| 179 | + :value="item.value"> | ||
| 180 | + <span style="float: left">{{ item.label }}</span> | ||
| 181 | + <span style="float: right; color: #8492a6; font-size: 13px">{{ item.value }}</span> | ||
| 182 | + </el-option> | ||
| 183 | + </el-select> | ||
| 184 | + </el-form-item> | ||
| 185 | + <el-form-item label="企业代码类型" prop="shpCompnyType"> | ||
| 186 | + <el-select | ||
| 187 | + v-model="temp.shpCompnyType" | ||
| 188 | + filterable | ||
| 189 | + placeholder="请选择企业代码类型" > | ||
| 190 | + <el-option | ||
| 191 | + v-for="item in shpCompnyTypeOption" | ||
| 192 | + :key="item.value" | ||
| 193 | + :label="item.label" | ||
| 194 | + :value="item.value" /> | ||
| 195 | + </el-select> | ||
| 196 | + </el-form-item> | ||
| 197 | + <el-form-item prop="shpCity"> | ||
| 198 | + <el-input v-model="temp.shpAddress" placeholder="企业代码"/> | ||
| 199 | + </el-form-item> | ||
| 200 | + </div> | ||
| 201 | + </el-col> | ||
| 202 | + </el-row> | ||
| 203 | + <div> | ||
| 204 | + <el-tag type="info" effect="plain"> | ||
| 205 | + 收货人信息 | ||
| 206 | + </el-tag> | ||
| 207 | + </div> | ||
| 208 | + <el-row type="flex" class="row-bg bg-purple"> | ||
| 209 | + <el-col :span="24"> | ||
| 210 | + <div class="grid-content"> | ||
| 211 | + <el-form-item label="公司" prop="shpCompany"> | ||
| 212 | + <el-input v-model="temp.shpCompany"/> | ||
| 213 | + </el-form-item> | ||
| 214 | + <el-form-item label="地址" prop="shpAddress"> | ||
| 215 | + <el-input v-model="temp.shpAddress"/> | ||
| 216 | + </el-form-item> | ||
| 217 | + <el-form-item label="城市" prop="shpCity"> | ||
| 218 | + <el-input v-model="temp.shpAddress"/> | ||
| 219 | + </el-form-item> | ||
| 220 | + <el-form-item label="邮编" prop="shpCity"> | ||
| 221 | + <el-input v-model="temp.shpAddress"/> | ||
| 222 | + </el-form-item> | ||
| 223 | + <el-form-item label="电话" prop="shpCity"> | ||
| 224 | + <el-input v-model="temp.shpAddress"/> | ||
| 225 | + </el-form-item> | ||
| 226 | + <el-form-item label="传真" prop="shpCity"> | ||
| 227 | + <el-input v-model="temp.shpAddress"/> | ||
| 228 | + </el-form-item> | ||
| 229 | + </div> | ||
| 230 | + <div> | ||
| 231 | + <el-form-item label="国家" prop="shpCountry"> | ||
| 232 | + <el-select | ||
| 233 | + :remote-method="remoteMethod" | ||
| 234 | + :loading="loading" | ||
| 235 | + v-model="temp.country" | ||
| 236 | + filterable | ||
| 237 | + remote | ||
| 238 | + placeholder="请选择" > | ||
| 239 | + <el-option | ||
| 240 | + v-for="item in countryOption" | ||
| 241 | + :key="item.value" | ||
| 242 | + :label="item.label" | ||
| 243 | + :value="item.value"> | ||
| 244 | + <span style="float: left">{{ item.label }}</span> | ||
| 245 | + <span style="float: right; color: #8492a6; font-size: 13px">{{ item.value }}</span> | ||
| 246 | + </el-option> | ||
| 247 | + </el-select> | ||
| 248 | + </el-form-item> | ||
| 249 | + <el-form-item label="企业代码类型" prop="shpCompnyType"> | ||
| 250 | + <el-select | ||
| 251 | + v-model="temp.shpCompnyType" | ||
| 252 | + filterable | ||
| 253 | + placeholder="请选择企业代码类型" > | ||
| 254 | + <el-option | ||
| 255 | + v-for="item in shpCompnyTypeOption" | ||
| 256 | + :key="item.value" | ||
| 257 | + :label="item.label" | ||
| 258 | + :value="item.value" /> | ||
| 259 | + </el-select> | ||
| 260 | + </el-form-item> | ||
| 261 | + <el-form-item prop="shpCity"> | ||
| 262 | + <el-input v-model="temp.shpAddress" placeholder="企业代码"/> | ||
| 263 | + </el-form-item> | ||
| 264 | + </div> | ||
| 265 | + </el-col> | ||
| 266 | + </el-row> | ||
| 267 | + <div> | ||
| 268 | + <el-tag type="info" effect="plain"> | ||
| 269 | + 危险品信息 | ||
| 270 | + </el-tag> | ||
| 271 | + </div> | ||
| 272 | + <el-row type="flex" class="row-bg bg-purple"> | ||
| 273 | + <el-col :span="24"> | ||
| 274 | + <el-form-item label="危险品信息" prop="shpCompnyType"> | ||
| 275 | + <el-select | ||
| 276 | + v-model="temp.dangerGoods" | ||
| 277 | + placeholder="请选择危险品类型" > | ||
| 278 | + <el-option | ||
| 279 | + v-for="item in dangerGoods" | ||
| 280 | + :key="item.value" | ||
| 281 | + :label="item.label" | ||
| 282 | + :value="item.value" > | ||
| 283 | + <span style="float: left">{{ item.label }}</span> | ||
| 284 | + <span style="float: right; color: #8492a6; font-size: 13px">{{ item.value }}</span> | ||
| 285 | + </el-option> | ||
| 286 | + </el-select> | ||
| 287 | + </el-form-item> | ||
| 288 | + <el-form-item label="危险品类别" prop="shpCity"> | ||
| 289 | + <el-input v-model="temp.shpAddress" placeholder="危险品类别"/> | ||
| 290 | + </el-form-item> | ||
| 291 | + </el-col> | ||
| 292 | + </el-row> | ||
| 293 | + <div> | ||
| 294 | + <el-tag type="info" effect="plain"> | ||
| 295 | + 交运信息 | ||
| 296 | + </el-tag> | ||
| 297 | + </div> | ||
| 298 | + <el-row type="flex" class="row-bg bg-purple"> | ||
| 299 | + <el-col :span="24"> | ||
| 300 | + <el-form-item label="包装" prop="shpCompnyType"> | ||
| 301 | + <el-select | ||
| 302 | + v-model="temp.goodsPackage" | ||
| 303 | + placeholder="请选择包装类型" > | ||
| 304 | + <el-option | ||
| 305 | + v-for="item in goodsPackage" | ||
| 306 | + :key="item.value" | ||
| 307 | + :label="item.label" | ||
| 308 | + :value="item.value" /> | ||
| 309 | + </el-select> | ||
| 310 | + </el-form-item> | ||
| 311 | + <el-form-item label="尺寸" prop="shpCity"> | ||
| 312 | + <el-input v-model="temp.shpAddress" placeholder="请输入尺寸"/> | ||
| 313 | + </el-form-item> | ||
| 314 | + <el-form-item label="计费重量" prop="shpCity"> | ||
| 315 | + <el-input v-model="temp.shpAddress" placeholder="请输入计费重量"/> | ||
| 316 | + </el-form-item> | ||
| 317 | + <el-form-item label="体积" prop="shpCity"> | ||
| 318 | + <el-input v-model="temp.shpAddress" placeholder="请输入体积"/> | ||
| 319 | + </el-form-item> | ||
| 320 | + </el-col> | ||
| 321 | + </el-row> | ||
| 322 | + <el-row type="flex" class="row-bg bg-purple"> | ||
| 323 | + <el-col :span="24"> | ||
| 324 | + <div class="remark"> | ||
| 325 | + <el-form-item label="备注" prop="shpCity" inline-message="false"> | ||
| 326 | + <el-input | ||
| 327 | + v-model="temp.shpAddress" | ||
| 328 | + type="textarea" | ||
| 329 | + placeholder="其他需要备注的信息" | ||
| 330 | + maxlength="30" | ||
| 331 | + show-word-limit | ||
| 332 | + /> | ||
| 333 | + </el-form-item> | ||
| 334 | + </div> | ||
| 335 | + </el-col> | ||
| 336 | + </el-row> | ||
| 337 | + </el-form> | ||
| 338 | + | ||
| 339 | + <div slot="footer" class="dialog-footer"> | ||
| 340 | + <el-button @click="dialogFormVisible = false">{{ $t('table.cancel') }}</el-button> | ||
| 341 | + <el-button type="primary" @click="dialogStatus==='create'?createData():updateData()">{{ $t('table.confirm') }}</el-button> | ||
| 342 | + </div> | ||
| 343 | + </el-dialog> | ||
| 344 | + | ||
| 345 | + </div> | ||
| 346 | +</template> | ||
| 347 | + | ||
| 348 | +<script> | ||
| 349 | +/** | ||
| 350 | + Auth: Lei.j1ang | ||
| 351 | + Created: 2018/1/19-14:54 | ||
| 352 | +*/ | ||
| 353 | + | ||
| 354 | +import treeTable from '@/components/TreeTable' | ||
| 355 | +import treeToArray from './customEval' | ||
| 356 | +import Pagination from '@/components/Pagination' | ||
| 357 | +import waves from '@/directive/waves' // Waves directive | ||
| 358 | +import country from '@/utils/country.js' | ||
| 359 | +import companyType from '@/utils/companyType.js' | ||
| 360 | +import dangerGoods from '@/utils/dangerGoods.js' | ||
| 361 | +import goodsPackage from '@/utils/goodsPackage.js' | ||
| 362 | + | ||
| 363 | +const calendarTypeOptions = [ | ||
| 364 | + { key: 'CN', display_name: 'China' }, | ||
| 365 | + { key: 'US', display_name: 'USA' }, | ||
| 366 | + { key: 'JP', display_name: 'Japan' }, | ||
| 367 | + { key: 'EU', display_name: 'Eurozone' } | ||
| 368 | +] | ||
| 369 | + | ||
| 370 | +// arr to obj ,such as { CN : "China", US : "USA" } | ||
| 371 | +const calendarTypeKeyValue = calendarTypeOptions.reduce((acc, cur) => { | ||
| 372 | + acc[cur.key] = cur.display_name | ||
| 373 | + return acc | ||
| 374 | +}, {}) | ||
| 375 | + | ||
| 376 | +treeTable.expandAll = { | ||
| 377 | + type: Boolean, | ||
| 378 | + default: false | ||
| 379 | +} | ||
| 380 | + | ||
| 381 | +export default { | ||
| 382 | + name: 'CustomTreeTableDemo', | ||
| 383 | + components: { treeTable, Pagination }, | ||
| 384 | + directives: { waves }, | ||
| 385 | + filters: { | ||
| 386 | + statusFilter(status) { | ||
| 387 | + const statusMap = { | ||
| 388 | + 10003: '', | ||
| 389 | + 41301: 'success', | ||
| 390 | + 10002: 'info', | ||
| 391 | + 10000: 'danger', | ||
| 392 | + 45103: 'warning', | ||
| 393 | + wrong: 'exception' | ||
| 394 | + } | ||
| 395 | + return statusMap[status] | ||
| 396 | + }, | ||
| 397 | + typeFilter(type) { | ||
| 398 | + return calendarTypeKeyValue[type] | ||
| 399 | + } | ||
| 400 | + }, | ||
| 401 | + data() { | ||
| 402 | + return { | ||
| 403 | + func: treeToArray, | ||
| 404 | + expandAll: true, | ||
| 405 | + total: 1, | ||
| 406 | + resend: true, | ||
| 407 | + listLoading: true, | ||
| 408 | + multipleSelection: [], | ||
| 409 | + dialogFormVisible: false, | ||
| 410 | + dialogStatus: '', | ||
| 411 | + country: country, | ||
| 412 | + countryOption: [], | ||
| 413 | + shpCompnyTypeOption: [], | ||
| 414 | + dangerGoods: dangerGoods, | ||
| 415 | + goodsPackage: goodsPackage, | ||
| 416 | + textMap: { | ||
| 417 | + update: '编辑', | ||
| 418 | + create: '添加' | ||
| 419 | + }, | ||
| 420 | + listQuery: { | ||
| 421 | + page: 1, | ||
| 422 | + limit: 20, | ||
| 423 | + waybillNo: '', | ||
| 424 | + flight: '', | ||
| 425 | + flightDate: '', | ||
| 426 | + custom: '' | ||
| 427 | + }, | ||
| 428 | + temp: { | ||
| 429 | + id: undefined, | ||
| 430 | + waybillNo: '', | ||
| 431 | + houseWaybillNo: '', | ||
| 432 | + custom: '4604', | ||
| 433 | + flight: '', | ||
| 434 | + flightDate: '', | ||
| 435 | + oriStation: 'CGO', | ||
| 436 | + desStation: '', | ||
| 437 | + maniPiece: undefined, | ||
| 438 | + maniWeight: undefined | ||
| 439 | + }, | ||
| 440 | + manifestCustoms: ['4604', '4620', '4613'], | ||
| 441 | + data: [ | ||
| 442 | + { | ||
| 443 | + id: 0, | ||
| 444 | + waybillNo: '580-20728399', | ||
| 445 | + houseWaybillNo: '', | ||
| 446 | + custom: '4604', | ||
| 447 | + flight: 'CV9733', | ||
| 448 | + flightDate: '2019-06-21', | ||
| 449 | + oriStation: 'LUX', | ||
| 450 | + desStation: 'CGO', | ||
| 451 | + maniPiece: 50, | ||
| 452 | + maniWeight: 21321, | ||
| 453 | + status: '41301', | ||
| 454 | + customText: ' 预配舱单主要数据传输成功。', | ||
| 455 | + customComplate: 25 | ||
| 456 | + }, | ||
| 457 | + { | ||
| 458 | + id: 1, | ||
| 459 | + waybillNo: '580-20728396', | ||
| 460 | + houseWaybillNo: '', | ||
| 461 | + custom: '4604', | ||
| 462 | + flight: 'CV9731', | ||
| 463 | + flightDate: '2019-06-21', | ||
| 464 | + oriStation: 'LUX', | ||
| 465 | + desStation: 'CGO', | ||
| 466 | + maniPiece: 50, | ||
| 467 | + maniWeight: 21321, | ||
| 468 | + status: 'wrong', | ||
| 469 | + customText: ' 预配回执异常 ', | ||
| 470 | + customComplate: 25, | ||
| 471 | + children: [ | ||
| 472 | + { | ||
| 473 | + id: 2, | ||
| 474 | + waybillNo: '580-20728396', | ||
| 475 | + houseWaybillNo: 'ADDSS21231', | ||
| 476 | + custom: '4604', | ||
| 477 | + flight: 'CV9731', | ||
| 478 | + flightDate: '2019-06-21', | ||
| 479 | + oriStation: 'LUX', | ||
| 480 | + desStation: 'CGO', | ||
| 481 | + maniPiece: 50, | ||
| 482 | + maniWeight: 21321, | ||
| 483 | + status: '10002', | ||
| 484 | + customText: ' 已暂存', | ||
| 485 | + customComplate: 0 | ||
| 486 | + }, | ||
| 487 | + { | ||
| 488 | + id: 3, | ||
| 489 | + waybillNo: '580-20728396', | ||
| 490 | + houseWaybillNo: 'SDE3411', | ||
| 491 | + custom: '4604', | ||
| 492 | + flight: 'CV9731', | ||
| 493 | + flightDate: '2019-06-21', | ||
| 494 | + oriStation: 'LUX', | ||
| 495 | + desStation: 'CGO', | ||
| 496 | + maniPiece: 50, | ||
| 497 | + maniWeight: 21321, | ||
| 498 | + status: '45103', | ||
| 499 | + customText: ' 45103 该提(运)单的运抵报告重复申报,海关审核不通过。 关区代码:4604。', | ||
| 500 | + customComplate: 100 | ||
| 501 | + }, | ||
| 502 | + { | ||
| 503 | + id: 4, | ||
| 504 | + waybillNo: '580-20728396', | ||
| 505 | + houseWaybillNo: 'SDE3411', | ||
| 506 | + custom: '4604', | ||
| 507 | + flight: 'CV9731', | ||
| 508 | + flightDate: '2019-06-21', | ||
| 509 | + oriStation: 'LUX', | ||
| 510 | + desStation: 'CGO', | ||
| 511 | + maniPiece: 50, | ||
| 512 | + maniWeight: 21321, | ||
| 513 | + status: '10000', | ||
| 514 | + customText: ' 已删除 ', | ||
| 515 | + customComplate: 50 | ||
| 516 | + } | ||
| 517 | + ] | ||
| 518 | + }, | ||
| 519 | + { | ||
| 520 | + id: 4, | ||
| 521 | + waybillNo: '580-20728391', | ||
| 522 | + houseWaybillNo: '', | ||
| 523 | + custom: '4604', | ||
| 524 | + flight: 'KA740', | ||
| 525 | + flightDate: '2019-06-29', | ||
| 526 | + oriStation: 'LUX', | ||
| 527 | + desStation: 'CGO', | ||
| 528 | + maniPiece: 50, | ||
| 529 | + maniWeight: 21321, | ||
| 530 | + status: '10003', | ||
| 531 | + customText: ' 已发送预配舱单 ' | ||
| 532 | + } | ||
| 533 | + ], | ||
| 534 | + pickerOptions: { | ||
| 535 | + shortcuts: [ | ||
| 536 | + { | ||
| 537 | + text: '今天', | ||
| 538 | + onClick(picker) { | ||
| 539 | + picker.$emit('pick', new Date()) | ||
| 540 | + } | ||
| 541 | + }, | ||
| 542 | + { | ||
| 543 | + text: '昨天', | ||
| 544 | + onClick(picker) { | ||
| 545 | + const date = new Date() | ||
| 546 | + date.setTime(date.getTime() - 3600 * 1000 * 24) | ||
| 547 | + picker.$emit('pick', date) | ||
| 548 | + } | ||
| 549 | + }, | ||
| 550 | + { | ||
| 551 | + text: '明天', | ||
| 552 | + onClick(picker) { | ||
| 553 | + const date = new Date() | ||
| 554 | + date.setTime(date.getTime() + 3600 * 1000 * 24) | ||
| 555 | + picker.$emit('pick', date) | ||
| 556 | + } | ||
| 557 | + }, | ||
| 558 | + { | ||
| 559 | + text: '一周前', | ||
| 560 | + onClick(picker) { | ||
| 561 | + const date = new Date() | ||
| 562 | + date.setTime(date.getTime() - 3600 * 1000 * 24 * 7) | ||
| 563 | + picker.$emit('pick', date) | ||
| 564 | + } | ||
| 565 | + } | ||
| 566 | + ] | ||
| 567 | + }, | ||
| 568 | + args: [null, null, 'timeLine'], | ||
| 569 | + rules: { | ||
| 570 | + maniWeight: [{ type: 'number', required: true, message: '重量必须为数字', trigger: 'blur' }], | ||
| 571 | + maniPiece: [{ type: 'number', required: true, message: '件数必须为数字', trigger: 'blur' }], | ||
| 572 | + desStation: [{ required: true, message: '运单目的地必须输入', trigger: 'blur' }], | ||
| 573 | + oriStation: [{ required: true, message: '运单起始站必须数据', trigger: 'change' }], | ||
| 574 | + flightDate: [{ type: 'date', required: true, message: '航班日期必须输入', trigger: 'change' }], | ||
| 575 | + flight: [{ required: true, message: '航班号必须输入', trigger: 'blur' }], | ||
| 576 | + custom: [{ required: true, message: '关区代码必须选择', trigger: 'change' }], | ||
| 577 | + waybillNo: [{ required: true, message: '运单号必须输入', trigger: 'blur' }] | ||
| 578 | + } | ||
| 579 | + } | ||
| 580 | + }, | ||
| 581 | + methods: { | ||
| 582 | + message(row) { | ||
| 583 | + this.$message.info(row.event) | ||
| 584 | + }, | ||
| 585 | + sortChange(data) { | ||
| 586 | + const { prop, order } = data | ||
| 587 | + if (prop === 'id') { | ||
| 588 | + this.sortByID(order) | ||
| 589 | + } | ||
| 590 | + }, | ||
| 591 | + sortByID(order) { | ||
| 592 | + if (order === 'ascending') { | ||
| 593 | + this.listQuery.sort = '+id' | ||
| 594 | + } else { | ||
| 595 | + this.listQuery.sort = '-id' | ||
| 596 | + } | ||
| 597 | + this.handleFilter() | ||
| 598 | + }, | ||
| 599 | + handleUpdate(row) { | ||
| 600 | + this.temp = Object.assign({}, row) // copy obj | ||
| 601 | + this.temp.timestamp = new Date(this.temp.timestamp) | ||
| 602 | + this.dialogStatus = 'update' | ||
| 603 | + this.dialogFormVisible = true | ||
| 604 | + this.$nextTick(() => { | ||
| 605 | + this.$refs[''].clearValidate() | ||
| 606 | + }) | ||
| 607 | + }, | ||
| 608 | + handleModifyStatus(row, status) { | ||
| 609 | + this.$message({ | ||
| 610 | + message: '操作成功', | ||
| 611 | + type: 'success' | ||
| 612 | + }) | ||
| 613 | + row.status = status | ||
| 614 | + }, | ||
| 615 | + getList() { | ||
| 616 | + | ||
| 617 | + }, | ||
| 618 | + handleSelectionChange(val) { | ||
| 619 | + this.multipleSelection = val | ||
| 620 | + }, | ||
| 621 | + resetTemp() { | ||
| 622 | + this.temp = { | ||
| 623 | + id: undefined, | ||
| 624 | + waybillNo: '', | ||
| 625 | + houseWaybillNo: '', | ||
| 626 | + custom: '4604', | ||
| 627 | + flight: '', | ||
| 628 | + flightDate: '', | ||
| 629 | + oriStation: 'CGO', | ||
| 630 | + desStation: '', | ||
| 631 | + maniPiece: undefined, | ||
| 632 | + maniWeight: undefined | ||
| 633 | + } | ||
| 634 | + }, | ||
| 635 | + handleCreate() { | ||
| 636 | + this.resetTemp() | ||
| 637 | + this.dialogStatus = 'create' | ||
| 638 | + this.dialogFormVisible = true | ||
| 639 | + this.$nextTick(() => { | ||
| 640 | + this.$refs[''].clearValidate() | ||
| 641 | + }) | ||
| 642 | + }, | ||
| 643 | + remoteMethod(query) { | ||
| 644 | + if (query !== '') { | ||
| 645 | + this.loading = true | ||
| 646 | + setTimeout(() => { | ||
| 647 | + this.loading = false | ||
| 648 | + this.countryOption = this.country.filter(item => { | ||
| 649 | + return item.value.toUpperCase() | ||
| 650 | + .indexOf(query.toUpperCase()) > -1 | ||
| 651 | + }) | ||
| 652 | + this.shpCompnyTypeOption = companyType.filter(item => { | ||
| 653 | + return item.value.toUpperCase() | ||
| 654 | + .indexOf(query.toUpperCase()) > -1 | ||
| 655 | + }) | ||
| 656 | + }, 200) | ||
| 657 | + } else { | ||
| 658 | + this.countryOption = [] | ||
| 659 | + } | ||
| 660 | + } | ||
| 661 | + } | ||
| 662 | +} | ||
| 663 | +</script> | ||
| 664 | +<style> | ||
| 665 | + .el-row { | ||
| 666 | + margin-bottom: 20px; | ||
| 667 | + &:last-child { | ||
| 668 | + margin-bottom: 0; | ||
| 669 | + } | ||
| 670 | + } | ||
| 671 | + .el-col { | ||
| 672 | + border-radius: 4px; | ||
| 673 | + } | ||
| 674 | + .bg-purple-dark { | ||
| 675 | + background: #99a9bf; | ||
| 676 | + } | ||
| 677 | + .bg-purple { | ||
| 678 | + background: #d3dce6; | ||
| 679 | + } | ||
| 680 | + .bg-purple-light { | ||
| 681 | + background: #e5e9f2; | ||
| 682 | + } | ||
| 683 | + .grid-content { | ||
| 684 | + border-radius: 4px; | ||
| 685 | + min-height: 36px; | ||
| 686 | + } | ||
| 687 | + .row-bg { | ||
| 688 | + padding: 10px 0; | ||
| 689 | + background-color: #f9fafc; | ||
| 690 | + } | ||
| 691 | + .el-progress.is-warning .el-progress-bar__inner{ | ||
| 692 | + background-color:#E6A23C | ||
| 693 | + } | ||
| 694 | + .remark textarea{ | ||
| 695 | + width: 600px; | ||
| 696 | + } | ||
| 697 | +</style> | ||
| 698 | + |
src/views/agent/customEval.js
0 → 100755
| 1 | +/** | ||
| 2 | +* @Author: jianglei | ||
| 3 | +* @Date: 2017-10-12 12:06:49 | ||
| 4 | +*/ | ||
| 5 | +'use strict' | ||
| 6 | +import Vue from 'vue' | ||
| 7 | +export default function treeToArray(data, expandAll, parent, level, item) { | ||
| 8 | + const marLTemp = [] | ||
| 9 | + let tmp = [] | ||
| 10 | + Array.from(data).forEach(function(record) { | ||
| 11 | + if (record._expanded === undefined) { | ||
| 12 | + Vue.set(record, '_expanded', expandAll) | ||
| 13 | + } | ||
| 14 | + let _level = 1 | ||
| 15 | + if (level !== undefined && level !== null) { | ||
| 16 | + _level = level + 1 | ||
| 17 | + } | ||
| 18 | + Vue.set(record, '_level', _level) | ||
| 19 | + // 如果有父元素 | ||
| 20 | + if (parent) { | ||
| 21 | + Vue.set(record, 'parent', parent) | ||
| 22 | + // 如果父元素有偏移量,需要计算在this的偏移量中 | ||
| 23 | + // 偏移量还与前面同级元素有关,需要加上前面所有元素的长度和 | ||
| 24 | + if (!marLTemp[_level]) { | ||
| 25 | + marLTemp[_level] = 0 | ||
| 26 | + } | ||
| 27 | + Vue.set(record, '_marginLeft', marLTemp[_level] + parent._marginLeft) | ||
| 28 | + Vue.set(record, '_width', record[item] / parent[item] * parent._width) | ||
| 29 | + // 在本次计算过偏移量后加上自己长度,以供下一个元素使用 | ||
| 30 | + marLTemp[_level] += record._width | ||
| 31 | + } else { | ||
| 32 | + // 如果为根 | ||
| 33 | + // 初始化偏移量存储map | ||
| 34 | + marLTemp[record.id] = [] | ||
| 35 | + // map中是一个数组,存储的是每级的长度和 | ||
| 36 | + // 初始情况下为0 | ||
| 37 | + marLTemp[record.id][_level] = 0 | ||
| 38 | + Vue.set(record, '_marginLeft', 0) | ||
| 39 | + Vue.set(record, '_width', 1) | ||
| 40 | + } | ||
| 41 | + tmp.push(record) | ||
| 42 | + if (record.children && record.children.length > 0) { | ||
| 43 | + const children = treeToArray(record.children, expandAll, record, _level, item) | ||
| 44 | + tmp = tmp.concat(children) | ||
| 45 | + } | ||
| 46 | + }) | ||
| 47 | + return tmp | ||
| 48 | +} |
| @@ -274,14 +274,14 @@ | @@ -274,14 +274,14 @@ | ||
| 274 | }; | 274 | }; |
| 275 | this.listLoading = true; | 275 | this.listLoading = true; |
| 276 | getUserList(para).then((res) => { | 276 | getUserList(para).then((res) => { |
| 277 | - this.total = res.data.total; | ||
| 278 | - this.users = res.data.list; | 277 | + let response = res.data.data; |
| 278 | + this.total = response.total; | ||
| 279 | + this.users = response.list; | ||
| 279 | this.listLoading = false; | 280 | this.listLoading = false; |
| 280 | //NProgress.done(); | 281 | //NProgress.done(); |
| 281 | }).catch((error) => { | 282 | }).catch((error) => { |
| 282 | this.listLoading = false; | 283 | this.listLoading = false; |
| 283 | - | ||
| 284 | - alert(error); | 284 | + this.$message.error(error.toString()); |
| 285 | }); | 285 | }); |
| 286 | 286 | ||
| 287 | }, | 287 | }, |
-
请 注册 或 登录 后发表评论