正在显示
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 | }, |
-
请 注册 或 登录 后发表评论