Commit a86b16bba66bd2283ef0acc24ff86ac1ef8adb67
1 parent
0bd81688e7
Exists in
master
auto commit the code by alias command
Showing
20 changed files
with
799 additions
and
138 deletions
Show diff stats
.env.production
1 | # just a flag | 1 | # just a flag |
2 | ENV = 'production' | 2 | ENV = 'production' |
3 | 3 | ||
4 | # base api | 4 | # base api |
5 | VUE_APP_BASE_API = '/prod-api' | 5 | #VUE_APP_BASE_API = '/prod-api' |
6 | 6 | VUE_APP_BASE_API = 'https://api.glass.xiuyetang.com/' | |
7 | 7 |
mock/index.js
1 | import Mock from 'mockjs' | 1 | import Mock from 'mockjs' |
2 | import { param2Obj } from '../src/utils' | 2 | import { |
3 | param2Obj | ||
4 | } from '../src/utils' | ||
3 | 5 | ||
4 | import user from './user' | 6 | import user from './user' |
5 | import role from './role' | 7 | import role from './role' |
8 | import prod from './prod' | ||
6 | import article from './article' | 9 | import article from './article' |
7 | import search from './remote-search' | 10 | import search from './remote-search' |
8 | 11 | //因为没有Mock上,所以会请求不到数据。报404 | |
9 | const mocks = [ | 12 | const mocks = [ |
10 | ...user, | 13 | ...user, |
11 | ...role, | 14 | ...role, |
12 | ...article, | 15 | ...article, |
16 | ...prod, | ||
13 | ...search | 17 | ...search |
14 | ] | 18 | ] |
15 | 19 | ||
16 | // for front mock | 20 | // for front mock |
17 | // please use it cautiously, it will redefine XMLHttpRequest, | 21 | // please use it cautiously, it will redefine XMLHttpRequest, |
18 | // which will cause many of your third-party libraries to be invalidated(like progress event). | 22 | // which will cause many of your third-party libraries to be invalidated(like progress event). |
19 | export function mockXHR() { | 23 | export function mockXHR() { |
20 | // mock patch | 24 | // mock patch |
21 | // https://github.com/nuysoft/Mock/issues/300 | 25 | // https://github.com/nuysoft/Mock/issues/300 |
22 | Mock.XHR.prototype.proxy_send = Mock.XHR.prototype.send | 26 | Mock.XHR.prototype.proxy_send = Mock.XHR.prototype.send |
23 | Mock.XHR.prototype.send = function() { | 27 | Mock.XHR.prototype.send = function () { |
24 | if (this.custom.xhr) { | 28 | if (this.custom.xhr) { |
25 | this.custom.xhr.withCredentials = this.withCredentials || false | 29 | this.custom.xhr.withCredentials = this.withCredentials || false |
26 | 30 | ||
27 | if (this.responseType) { | 31 | if (this.responseType) { |
28 | this.custom.xhr.responseType = this.responseType | 32 | this.custom.xhr.responseType = this.responseType |
29 | } | 33 | } |
30 | } | 34 | } |
31 | this.proxy_send(...arguments) | 35 | this.proxy_send(...arguments) |
32 | } | 36 | } |
33 | 37 | ||
34 | function XHR2ExpressReqWrap(respond) { | 38 | function XHR2ExpressReqWrap(respond) { |
35 | return function(options) { | 39 | return function (options) { |
36 | let result = null | 40 | let result = null |
37 | if (respond instanceof Function) { | 41 | if (respond instanceof Function) { |
38 | const { body, type, url } = options | 42 | const { |
43 | body, | ||
44 | type, | ||
45 | url | ||
46 | } = options | ||
39 | // https://expressjs.com/en/4x/api.html#req | 47 | // https://expressjs.com/en/4x/api.html#req |
40 | result = respond({ | 48 | result = respond({ |
41 | method: type, | 49 | method: type, |
42 | body: JSON.parse(body), | 50 | body: JSON.parse(body), |
43 | query: param2Obj(url) | 51 | query: param2Obj(url) |
44 | }) | 52 | }) |
45 | } else { | 53 | } else { |
46 | result = respond | 54 | result = respond |
47 | } | 55 | } |
48 | return Mock.mock(result) | 56 | return Mock.mock(result) |
49 | } | 57 | } |
50 | } | 58 | } |
51 | 59 | ||
52 | for (const i of mocks) { | 60 | for (const i of mocks) { |
53 | Mock.mock(new RegExp(i.url), i.type || 'get', XHR2ExpressReqWrap(i.response)) | 61 | Mock.mock(new RegExp(i.url), i.type || 'get', XHR2ExpressReqWrap(i.response)) |
54 | } | 62 | } |
55 | } | 63 | } |
56 | 64 | ||
57 | // for mock server | 65 | // for mock server |
58 | const responseFake = (url, type, respond) => { | 66 | const responseFake = (url, type, respond) => { |
59 | return { | 67 | return { |
60 | url: new RegExp(`${process.env.VUE_APP_BASE_API}${url}`), | 68 | url: new RegExp(`${process.env.VUE_APP_BASE_API}${url}`), |
61 | type: type || 'get', | 69 | type: type || 'get', |
62 | response(req, res) { | 70 | response(req, res) { |
63 | console.log('request invoke:' + req.path) | 71 | console.log('request invoke:' + req.path) |
64 | res.json(Mock.mock(respond instanceof Function ? respond(req, res) : respond)) | 72 | res.json(Mock.mock(respond instanceof Function ? respond(req, res) : respond)) |
65 | } | 73 | } |
66 | } | 74 | } |
67 | } | 75 | } |
68 | 76 | ||
69 | export default mocks.map(route => { | 77 | export default mocks.map(route => { |
70 | return responseFake(route.url, route.type, route.response) | 78 | return responseFake(route.url, route.type, route.response) |
71 | }) | 79 | }) |
72 | 80 |
mock/prod.js
1 | import Mock from 'mockjs' | 1 | import Mock from 'mockjs' |
2 | // import logoPath from "~@/assets/img/yp_logo.jpeg" | 2 | // import logoPath from "~@/assets/img/yp_logo.jpeg" |
3 | 3 | ||
4 | const List = [] | 4 | const List = [] |
5 | const count = 20 | 5 | const count = 20 |
6 | 6 | ||
7 | const baseContent = '<p>I am testing data, I am testing data.</p><p></p>' | 7 | const baseContent = '<p>I am testing data, I am testing data.</p><p></p>' |
8 | // const image_uri = logoPath | 8 | // const image_uri = logoPath |
9 | const image_uri = 'https://wpimg.wallstcn.com/360e4842-4db5-42d0-b078-f9a84a825546.gif' | 9 | const image_uri = 'https://wpimg.wallstcn.com/360e4842-4db5-42d0-b078-f9a84a825546.gif' |
10 | 10 | ||
11 | for (let i = 0; i < count; i++) { | 11 | for (let i = 0; i < count; i++) { |
12 | List.push(Mock.mock({ | 12 | List.push(Mock.mock({ |
13 | pid: '@increment', | 13 | pid: '@increment', //产品id |
14 | pname: '@title(5,10)', | 14 | pname: '01-8701志平防蓝光-防辐射电脑网课眼镜,TR90弹性漆,近视镜,青春潮流', //产品名移交 |
15 | timestamp: +Mock.Random.date('T'), | 15 | timestamp: +Mock.Random.date('T'), //产品时间 |
16 | shoper: '@first', //所属工厂 | 16 | shoper: '@first', //所属工厂 |
17 | salescount: '@first', //购买次数 | 17 | salescount: '@first', //购买次数 |
18 | importance: '@integer(1, 3)', //排序权重 | 18 | importance: '@integer(1, 3)', //排序-权重 |
19 | prod_info_weight: '@integer(1, 3)', //重量 | 19 | prod_info_weight: '@integer(1, 3)', //参数--->重量 |
20 | prod_info_leg_long: '@integer(1, 3)', //腿长 | 20 | prod_info_leg_long: '@integer(1, 3)', //参数--->腿长 |
21 | prod_info_glass_width: '@integer(1, 3)', //镜宽 | 21 | prod_info_glass_width: '@integer(1, 3)', //参数--->镜宽 |
22 | prod_info_glass_height: '@integer(1, 3)', //镜高 | 22 | prod_info_glass_height: '@integer(1, 3)', //参数--->镜高 |
23 | prod_info_frame_width: '@integer(1, 3)', //框宽 | 23 | prod_info_frame_width: '@integer(1, 3)', //参数--->框宽 |
24 | prod_info_frame_height: '@integer(1, 3)', //框高 | 24 | prod_info_frame_height: '@integer(1, 3)', //参数--->框高 |
25 | prod_info_norse_width: '@integer(1, 3)', //鼻宽 | 25 | prod_info_norse_width: '@integer(1, 3)', //参数--->鼻宽 |
26 | prod_info_window_pic: [], //鼻宽 | 26 | prod_info_window_pic: [], //鼻宽 |
27 | image_uri: image_uri | 27 | image_uri: image_uri, |
28 | prod_memo: '', | ||
29 | // 'type|1': ['CN', 'US', 'JP', 'EU'], | ||
30 | // 'status|1': ['published', 'draft'], | ||
31 | 'type|1': ['CN', 'US', 'JP', 'EU'], //本产品销售区域 | ||
32 | 'prod_status|1': ['published', 'draft'], //状态,上线-下线 | ||
33 | judge_list: [], //评论管理 | ||
34 | sku_list: [], //sku清单 | ||
35 | sku_attr: [], //sku属性 | ||
28 | })) | 36 | })) |
29 | } | 37 | } |
30 | 38 | ||
31 | export default [{ | 39 | export default [{ |
32 | url: '/yp/prod/list', | 40 | url: '/yp/prod/list', |
33 | type: 'post', | 41 | type: 'post', |
34 | response: config => { | 42 | response: config => { |
35 | const { | 43 | const { |
36 | importance, | 44 | importance, |
37 | type, | 45 | type, |
38 | title, | 46 | pname, |
39 | page = 1, | 47 | page = 1, |
40 | limit = 20, | 48 | limit = 20, |
41 | sort | 49 | // sort |
42 | } = config.query | 50 | } = config.query |
43 | 51 | ||
44 | let mockList = List.filter(item => { | 52 | let mockList = List.filter(item => { |
45 | if (importance && item.importance !== +importance) return false | 53 | if (importance && item.importance !== +importance) return false |
46 | if (type && item.type !== type) return false | 54 | if (type && item.type !== type) return false |
47 | if (title && item.title.indexOf(title) < 0) return false | 55 | if (pname && item.pname.indexOf(pname) < 0) return false |
48 | return true | 56 | return true |
49 | }) | 57 | }) |
50 | 58 | ||
51 | if (sort === '-id') { | 59 | // if (sort === '-pid') { |
52 | mockList = mockList.reverse() | 60 | // mockList = mockList.reverse() |
53 | } | 61 | // } |
54 | |||
55 | const pageList = mockList.filter((item, index) => index < limit * page && index >= limit * (page - 1)) | 62 | const pageList = mockList.filter((item, index) => index < limit * page && index >= limit * (page - 1)) |
56 | 63 | ||
57 | return { | 64 | return { |
58 | code: 20000, | 65 | code: 20000, |
59 | data: { | 66 | data: { |
60 | total: mockList.length, | 67 | total: mockList.length, |
61 | items: pageList | 68 | items: pageList |
62 | } | 69 | } |
63 | } | 70 | } |
64 | } | 71 | } |
65 | }, | 72 | }, |
66 | |||
67 | { | 73 | { |
68 | url: '/yp/prod/detail', | 74 | url: '/yp/prod/detail', |
69 | type: 'get', | 75 | type: 'get', |
70 | response: config => { | 76 | response: config => { |
71 | const { | 77 | const { |
72 | id | 78 | pid |
73 | } = config.query | 79 | } = config.query |
74 | for (const prod of List) { | 80 | for (const prod of List) { |
75 | if (prod.id === +id) { | 81 | if (prod.pid === +pid) { |
76 | return { | 82 | return { |
77 | code: 20000, | 83 | code: 20000, |
78 | data: prod | 84 | data: prod |
79 | } | 85 | } |
80 | } | 86 | } |
81 | } | 87 | } |
82 | } | 88 | } |
83 | }, | 89 | }, |
84 | 90 | ||
85 | { | 91 | // { |
86 | url: '/yp/prod/pv', | 92 | // url: '/yp/prod/pv', |
87 | type: 'get', | 93 | // type: 'get', |
88 | response: _ => { | 94 | // response: _ => { |
89 | return { | 95 | // return { |
90 | code: 20000, | 96 | // code: 20000, |
91 | data: { | 97 | // data: { |
92 | pvData: [{ | 98 | // pvData: [{ |
93 | key: 'PC', | 99 | // key: 'PC', |
94 | pv: 1024 | 100 | // pv: 1024 |
95 | }, | 101 | // }, |
96 | { | 102 | // { |
97 | key: 'mobile', | 103 | // key: 'mobile', |
98 | pv: 1024 | 104 | // pv: 1024 |
99 | }, | 105 | // }, |
100 | { | 106 | // { |
101 | key: 'ios', | 107 | // key: 'ios', |
102 | pv: 1024 | 108 | // pv: 1024 |
103 | }, | 109 | // }, |
104 | { | 110 | // { |
105 | key: 'android', | 111 | // key: 'android', |
106 | pv: 1024 | 112 | // pv: 1024 |
107 | } | 113 | // } |
108 | ] | 114 | // ] |
109 | } | 115 | // } |
110 | } | 116 | // } |
111 | } | 117 | // } |
112 | }, | 118 | // }, |
113 | 119 | ||
114 | { | 120 | { |
115 | url: '/yp/prod/create', | 121 | url: '/yp/prod/create', |
116 | type: 'post', | 122 | type: 'post', |
117 | response: _ => { | 123 | response: _ => { |
118 | return { | 124 | return { |
119 | code: 20000, | 125 | code: 20000, |
120 | data: 'success' | 126 | data: 'success' |
121 | } | 127 | } |
122 | } | 128 | } |
123 | }, | 129 | }, |
124 | 130 | ||
125 | { | 131 | { |
126 | url: '/yp/prod/update', | 132 | url: '/yp/prod/update', |
127 | type: 'post', | 133 | type: 'post', |
128 | response: _ => { | 134 | response: _ => { |
129 | return { | 135 | return { |
130 | code: 20000, | 136 | code: 20000, |
131 | data: 'success' | 137 | data: 'success' |
132 | } | 138 | } |
133 | } | 139 | } |
134 | } | 140 | } |
src/api/prod.js
1 | import request from '@/utils/request' | 1 | import request from '@/utils/request' |
2 | 2 | ||
3 | // export const getPersonInfo = data => { | 3 | // export const getPersonInfo = data => { |
4 | // return service({ | 4 | // return service({ |
5 | // url: '/person_pay/getpersoninfo', | 5 | // url: '/person_pay/getpersoninfo', |
6 | // method: 'post', | 6 | // method: 'post', |
7 | // data | 7 | // data |
8 | // }) | 8 | // }) |
9 | // } | 9 | // } |
10 | 10 | ||
11 | export function fetchList(query) { | 11 | export function fetchList(query) { |
12 | return request({ | 12 | return request({ |
13 | url: '/yp/prod/list', | 13 | url: '/yp/prod/list', |
14 | method: 'post', | 14 | method: 'post', |
15 | params: query | 15 | data: query |
16 | }) | 16 | }) |
17 | } | 17 | } |
18 | 18 | ||
19 | export function fetchArticle(id) { | 19 | export function fetchProd(pid) { |
20 | return request({ | 20 | return request({ |
21 | url: '/yp/prod/detail', | 21 | url: '/yp/prod/detail', |
22 | method: 'get', | 22 | method: 'get', |
23 | params: { | 23 | params: { |
24 | id | 24 | pid |
25 | } | 25 | } |
26 | }) | 26 | }) |
27 | } | 27 | } |
28 | 28 | ||
29 | export function fetchPv(pv) { | 29 | export function fetchPv(pv) { |
30 | return request({ | 30 | return request({ |
31 | url: '/yp/prod/pv', | 31 | url: '/yp/prod/pv', |
32 | method: 'get', | 32 | method: 'get', |
33 | params: { | 33 | params: { |
34 | pv | 34 | pv |
35 | } | 35 | } |
36 | }) | 36 | }) |
37 | } | 37 | } |
38 | 38 | ||
39 | export function createArticle(data) { | 39 | export function createArticle(data) { |
40 | return request({ | 40 | return request({ |
41 | url: '/yp/prod/create', | 41 | url: '/yp/prod/create', |
42 | method: 'post', | 42 | method: 'post', |
43 | data | 43 | data |
44 | }) | 44 | }) |
45 | } | 45 | } |
46 | 46 | ||
47 | export function updateArticle(data) { | 47 | export function updateArticle(data) { |
48 | return request({ | 48 | return request({ |
49 | url: '/yp/prod/update', | 49 | url: '/yp/prod/update', |
50 | method: 'post', | 50 | method: 'post', |
51 | data | 51 | data |
52 | }) | 52 | }) |
53 | } | 53 | } |
54 | 54 |
src/components/Pagination/index.vue
1 | <template> | 1 | <template> |
2 | <div :class="{'hidden':hidden}" class="pagination-container"> | 2 | <div |
3 | :class="{'hidden':hidden}" | ||
4 | class="pagination-container" | ||
5 | > | ||
3 | <el-pagination | 6 | <el-pagination |
4 | :background="background" | 7 | :background="background" |
5 | :current-page.sync="currentPage" | 8 | :current-page.sync="currentPage" |
6 | :page-size.sync="pageSize" | 9 | :page-size.sync="pageSize" |
7 | :layout="layout" | 10 | :layout="layout" |
8 | :page-sizes="pageSizes" | 11 | :page-sizes="pageSizes" |
9 | :total="total" | 12 | :total="total" |
10 | v-bind="$attrs" | 13 | v-bind="$attrs" |
11 | @size-change="handleSizeChange" | 14 | @size-change="handleSizeChange" |
12 | @current-change="handleCurrentChange" | 15 | @current-change="handleCurrentChange" |
13 | /> | 16 | /> |
14 | </div> | 17 | </div> |
15 | </template> | 18 | </template> |
16 | 19 | ||
17 | <script> | 20 | <script> |
18 | import { scrollTo } from '@/utils/scroll-to' | 21 | import { scrollTo } from '@/utils/scroll-to' |
19 | 22 | ||
20 | export default { | 23 | export default { |
21 | name: 'Pagination', | 24 | name: 'Pagination', |
22 | props: { | 25 | props: { |
23 | total: { | 26 | total: { |
24 | required: true, | 27 | required: true, |
25 | type: Number | 28 | type: Number |
26 | }, | 29 | }, |
27 | page: { | 30 | page: { |
28 | type: Number, | 31 | type: Number, |
29 | default: 1 | 32 | default: 1 |
30 | }, | 33 | }, |
31 | limit: { | 34 | limit: { |
32 | type: Number, | 35 | type: Number, |
33 | default: 20 | 36 | default: 20 |
34 | }, | 37 | }, |
35 | pageSizes: { | 38 | pageSizes: { |
36 | type: Array, | 39 | type: Array, |
37 | default() { | 40 | default() { |
38 | return [10, 20, 30, 50] | 41 | return [10, 20, 30, 50] |
39 | } | 42 | } |
40 | }, | 43 | }, |
41 | layout: { | 44 | layout: { |
42 | type: String, | 45 | type: String, |
43 | default: 'total, sizes, prev, pager, next, jumper' | 46 | default: 'total, sizes, prev, pager, next, jumper' |
44 | }, | 47 | }, |
45 | background: { | 48 | background: { |
46 | type: Boolean, | 49 | type: Boolean, |
47 | default: true | 50 | default: true |
48 | }, | 51 | }, |
49 | autoScroll: { | 52 | autoScroll: { |
50 | type: Boolean, | 53 | type: Boolean, |
51 | default: true | 54 | default: true |
52 | }, | 55 | }, |
53 | hidden: { | 56 | hidden: { |
54 | type: Boolean, | 57 | type: Boolean, |
55 | default: false | 58 | default: false |
56 | } | 59 | } |
57 | }, | 60 | }, |
58 | computed: { | 61 | computed: { |
59 | currentPage: { | 62 | currentPage: { |
60 | get() { | 63 | get() { |
61 | return this.page | 64 | return this.page |
62 | }, | 65 | }, |
63 | set(val) { | 66 | set(val) { |
64 | this.$emit('update:page', val) | 67 | this.$emit('update:page', val) |
65 | } | 68 | } |
66 | }, | 69 | }, |
67 | pageSize: { | 70 | pageSize: { |
68 | get() { | 71 | get() { |
69 | return this.limit | 72 | return this.limit |
70 | }, | 73 | }, |
71 | set(val) { | 74 | set(val) { |
72 | this.$emit('update:limit', val) | 75 | this.$emit('update:limit', val) |
73 | } | 76 | } |
74 | } | 77 | } |
75 | }, | 78 | }, |
76 | methods: { | 79 | methods: { |
77 | handleSizeChange(val) { | 80 | handleSizeChange(val) { |
78 | this.$emit('pagination', { page: this.currentPage, limit: val }) | 81 | this.$emit('pagination', { page: this.currentPage, limit: val }) |
79 | if (this.autoScroll) { | 82 | if (this.autoScroll) { |
80 | scrollTo(0, 800) | 83 | scrollTo(0, 800) |
81 | } | 84 | } |
82 | }, | 85 | }, |
83 | handleCurrentChange(val) { | 86 | handleCurrentChange(val) { |
84 | this.$emit('pagination', { page: val, limit: this.pageSize }) | 87 | this.$emit('pagination', { page: val, limit: this.pageSize }) |
85 | if (this.autoScroll) { | 88 | if (this.autoScroll) { |
86 | scrollTo(0, 800) | 89 | scrollTo(0, 800) |
87 | } | 90 | } |
88 | } | 91 | } |
89 | } | 92 | } |
90 | } | 93 | } |
91 | </script> | 94 | </script> |
92 | 95 | ||
93 | <style scoped> | 96 | <style scoped> |
94 | .pagination-container { | 97 | .pagination-container { |
95 | background: #fff; | 98 | background: #fff; |
96 | padding: 32px 16px; | 99 | padding: 32px 16px; |
97 | } | 100 | } |
98 | .pagination-container.hidden { | 101 | .pagination-container.hidden { |
99 | display: none; | 102 | display: none; |
100 | } | 103 | } |
101 | </style> | 104 | </style> |
102 | 105 |
src/lang/zh.js
1 | export default { | 1 | export default { |
2 | // 添加的新词条------start | 2 | // 添加的新词条------start |
3 | prod: { | 3 | prod: { |
4 | menu_title: 'products', | 4 | menu_title: 'products', |
5 | sku_modle_pic: '模型图', | 5 | sku_modle_pic: '模型图', |
6 | sku_buy_pic: '购买效果图', | 6 | sku_buy_pic: '购买效果图', |
7 | window_pic: '橱窗图', | 7 | window_pic: '橱窗图', |
8 | detail_pic: '详情图' | 8 | detail_pic: '详情图' |
9 | }, | 9 | }, |
10 | order: { | 10 | order: { |
11 | refunding: '退款中', | 11 | refunding: '退款中', |
12 | refunded: '退款完成', | 12 | refunded: '退款完成', |
13 | 13 | ||
14 | pay_pending: '待支付', | 14 | pay_pending: '待支付', |
15 | pay_finished: '支付完成', | 15 | pay_finished: '支付完成', |
16 | 16 | ||
17 | deliver_pre: '准备配送', | 17 | deliver_pre: '准备配送', |
18 | deliver_ing: '配送中', | 18 | deliver_ing: '配送中', |
19 | deliver_finished: '物流完成' | 19 | deliver_finished: '物流完成' |
20 | }, | 20 | }, |
21 | users: { | 21 | users: { |
22 | table: { | 22 | table: { |
23 | uid: '用户id', | 23 | uid: '用户id', |
24 | username: '用户名', | 24 | username: '用户名', |
25 | password: '密码', | 25 | password: '密码', |
26 | create_at: '注册时间', | 26 | create_at: '注册时间', |
27 | nickname: '昵称', | 27 | nickname: '昵称', |
28 | roles: '角色', | 28 | roles: '角色', |
29 | openid: 'openid', | 29 | openid: 'openid', |
30 | son_of_adv: '下线', | 30 | son_of_adv: '下线', |
31 | status: '当前状态', | 31 | status: '当前状态', |
32 | level: '等级', | 32 | level: '等级', |
33 | oper: '操作', | 33 | oper: '操作', |
34 | souceof: '上线', | 34 | souceof: '上线', |
35 | revernew: '收益', | 35 | revernew: '收益', |
36 | buyvalue: '消费价值', | 36 | buyvalue: '消费价值', |
37 | buywill: '消费潜力', | 37 | buywill: '消费潜力', |
38 | score: '积分', | 38 | score: '积分', |
39 | weixin: '微信', | 39 | weixin: '微信', |
40 | facebook: 'facebook', | 40 | facebook: 'facebook', |
41 | comefromperson: '来自人', | 41 | comefromperson: '来自人', |
42 | comefromplatform: '来自平台', | 42 | comefromplatform: '来自平台', |
43 | benifit: '提成', | 43 | benifit: '提成', |
44 | coupon: '优惠券', | 44 | coupon: '优惠券', |
45 | remark: '备注', | 45 | remark: '备注', |
46 | importance: '重要度', | 46 | importance: '重要度', |
47 | num: '数量' | 47 | num: '数量' |
48 | }, | 48 | }, |
49 | add: '添加', | 49 | add: '添加', |
50 | search: '搜索', | 50 | search: '搜索', |
51 | del: '删除', | 51 | del: '删除', |
52 | update: '修改', | 52 | update: '修改', |
53 | edit: '修改', | 53 | edit: '修改', |
54 | selectall: '全选' | 54 | selectall: '全选' |
55 | }, | 55 | }, |
56 | site: { | 56 | site: { |
57 | // seo:'seo', | 57 | // seo:'seo', |
58 | 58 | ||
59 | }, | 59 | }, |
60 | meta: { | 60 | meta: { |
61 | metadefine: '元定义' | 61 | metadefine: '元定义' |
62 | }, | 62 | }, |
63 | system: { | 63 | system: { |
64 | memu: '系统' | 64 | memu: '系统' |
65 | }, | 65 | }, |
66 | route: { | 66 | route: { |
67 | users: { | 67 | users: { |
68 | people: '用户', | 68 | people: '用户', |
69 | user: '普通用户', | 69 | user: '普通用户', |
70 | list: '列表', | 70 | list: '列表', |
71 | shoper: '厂商', | 71 | shoper: '厂商', |
72 | runner: '运营官', | 72 | runner: '运营官', |
73 | assistant: '操作员', | 73 | assistant: '操作员', |
74 | admin: '超级管理员' | 74 | admin: '超级管理员' |
75 | }, | 75 | }, |
76 | shopers: '厂商', | 76 | shopers: '厂商', |
77 | prods: { | 77 | prods: { |
78 | prod_menu: '产品', | 78 | prod_menu: '产品', |
79 | prodlist: '产品列表' | 79 | prodlist: '产品列表' |
80 | }, | 80 | }, |
81 | orders: '订单', | 81 | orders: '订单', |
82 | sites: '站点', | 82 | sites: { |
83 | sites: '站点', | ||
84 | siteList: '站点列表' | ||
85 | }, | ||
83 | metas: { | 86 | metas: { |
84 | metas: '元', | 87 | metas: '元', |
85 | list: '树' | 88 | list: '树' |
86 | }, | 89 | }, |
87 | systems: { | 90 | systems: { |
88 | systems: '系统设置', | 91 | systems: '系统设置', |
89 | sites: '站点设置', | 92 | sites: '站点设置', |
90 | money: '货币设置', | 93 | money: '货币设置', |
91 | industry: '行业设置', | 94 | industry: '行业设置', |
92 | template: '模版设置' | 95 | template: '模版设置' |
93 | }, | 96 | }, |
94 | // 添加的新词条------end | 97 | // 添加的新词条------end |
95 | dashboard: '首页', | 98 | dashboard: '首页', |
96 | documentation: '文档', | 99 | documentation: '文档', |
97 | guide: '引导页', | 100 | guide: '引导页', |
98 | permission: '权限测试页', | 101 | permission: '权限测试页', |
99 | rolePermission: '角色权限', | 102 | rolePermission: '角色权限', |
100 | pagePermission: '页面权限', | 103 | pagePermission: '页面权限', |
101 | directivePermission: '指令权限', | 104 | directivePermission: '指令权限', |
102 | icons: '图标', | 105 | icons: '图标', |
103 | components: '组件', | 106 | components: '组件', |
104 | tinymce: '富文本编辑器', | 107 | tinymce: '富文本编辑器', |
105 | markdown: 'Markdown', | 108 | markdown: 'Markdown', |
106 | jsonEditor: 'JSON 编辑器', | 109 | jsonEditor: 'JSON 编辑器', |
107 | dndList: '列表拖拽', | 110 | dndList: '列表拖拽', |
108 | splitPane: 'Splitpane', | 111 | splitPane: 'Splitpane', |
109 | avatarUpload: '头像上传', | 112 | avatarUpload: '头像上传', |
110 | dropzone: 'Dropzone', | 113 | dropzone: 'Dropzone', |
111 | sticky: 'Sticky', | 114 | sticky: 'Sticky', |
112 | countTo: 'Count To', | 115 | countTo: 'Count To', |
113 | componentMixin: '小组件', | 116 | componentMixin: '小组件', |
114 | backToTop: '返回顶部', | 117 | backToTop: '返回顶部', |
115 | dragDialog: '拖拽 Dialog', | 118 | dragDialog: '拖拽 Dialog', |
116 | dragSelect: '拖拽 Select', | 119 | dragSelect: '拖拽 Select', |
117 | dragKanban: '可拖拽看板', | 120 | dragKanban: '可拖拽看板', |
118 | charts: '图表', | 121 | charts: '图表', |
119 | keyboardChart: '键盘图表', | 122 | keyboardChart: '键盘图表', |
120 | lineChart: '折线图', | 123 | lineChart: '折线图', |
121 | mixChart: '混合图表', | 124 | mixChart: '混合图表', |
122 | example: '综合实例', | 125 | example: '综合实例', |
123 | nested: '路由嵌套', | 126 | nested: '路由嵌套', |
124 | menu1: '菜单1', | 127 | menu1: '菜单1', |
125 | 'menu1-1': '菜单 1-1', | 128 | 'menu1-1': '菜单 1-1', |
126 | 'menu1-2': '菜单 1-2', | 129 | 'menu1-2': '菜单 1-2', |
127 | 'menu1-2-1': '菜单 1-2-1', | 130 | 'menu1-2-1': '菜单 1-2-1', |
128 | 'menu1-2-2': '菜单 1-2-2', | 131 | 'menu1-2-2': '菜单 1-2-2', |
129 | 'menu1-3': '菜单 1-3', | 132 | 'menu1-3': '菜单 1-3', |
130 | menu2: '菜单 2', | 133 | menu2: '菜单 2', |
131 | Table: 'Table', | 134 | Table: 'Table', |
132 | dynamicTable: '动态 Table', | 135 | dynamicTable: '动态 Table', |
133 | dragTable: '拖拽 Table', | 136 | dragTable: '拖拽 Table', |
134 | inlineEditTable: 'Table 内编辑', | 137 | inlineEditTable: 'Table 内编辑', |
135 | complexTable: '综合 Table', | 138 | complexTable: '综合 Table', |
136 | tab: 'Tab', | 139 | tab: 'Tab', |
137 | form: '表单', | 140 | form: '表单', |
138 | createArticle: '创建文章', | 141 | createArticle: '创建文章', |
139 | editArticle: '编辑文章', | 142 | editArticle: '编辑文章', |
140 | articleList: '文章列表', | 143 | articleList: '文章列表', |
141 | errorPages: '错误页面', | 144 | errorPages: '错误页面', |
142 | page401: '401', | 145 | page401: '401', |
143 | page404: '404', | 146 | page404: '404', |
144 | errorLog: '错误日志', | 147 | errorLog: '错误日志', |
145 | excel: 'Excel', | 148 | excel: 'Excel', |
146 | exportExcel: '导出 Excel', | 149 | exportExcel: '导出 Excel', |
147 | selectExcel: '导出 已选择项', | 150 | selectExcel: '导出 已选择项', |
148 | mergeHeader: '导出 多级表头', | 151 | mergeHeader: '导出 多级表头', |
149 | uploadExcel: '上传 Excel', | 152 | uploadExcel: '上传 Excel', |
150 | zip: 'Zip', | 153 | zip: 'Zip', |
151 | pdf: 'PDF', | 154 | pdf: 'PDF', |
152 | exportZip: 'Export Zip', | 155 | exportZip: 'Export Zip', |
153 | theme: '换肤', | 156 | theme: '换肤', |
154 | clipboardDemo: 'Clipboard', | 157 | clipboardDemo: 'Clipboard', |
155 | i18n: '国际化', | 158 | i18n: '国际化', |
156 | externalLink: '外链', | 159 | externalLink: '外链', |
157 | profile: '个人中心' | 160 | profile: '个人中心' |
158 | }, | 161 | }, |
159 | navbar: { | 162 | navbar: { |
160 | dashboard: '首页', | 163 | dashboard: '首页', |
161 | github: '项目地址', | 164 | github: '项目地址', |
162 | logOut: '退出登录', | 165 | logOut: '退出登录', |
163 | profile: '个人中心', | 166 | profile: '个人中心', |
164 | theme: '换肤', | 167 | theme: '换肤', |
165 | size: '布局大小' | 168 | size: '布局大小' |
166 | }, | 169 | }, |
167 | login: { | 170 | login: { |
168 | runner: '运营官', | 171 | runner: '运营官', |
169 | shoper: '商家', | 172 | shoper: '商家', |
170 | assistant: '操作员', | 173 | assistant: '操作员', |
171 | signup: '注册', | 174 | signup: '注册', |
172 | forgetpassword: '忘记密码', | 175 | forgetpassword: '忘记密码', |
173 | rememberpassword: 'remember password', | 176 | rememberpassword: 'remember password', |
174 | 177 | ||
175 | title: '鱼皮出海--让我们荡起双浆', | 178 | title: '鱼皮出海--让我们荡起双浆', |
176 | logIn: '登录', | 179 | logIn: '登录', |
177 | username: '账号', | 180 | username: '账号', |
178 | password: '密码', | 181 | password: '密码', |
179 | any: '随便填', | 182 | any: '随便填', |
180 | thirdparty: '第三方登录', | 183 | thirdparty: '第三方登录', |
181 | thirdpartyTips: '本地不能模拟,请结合自己业务进行模拟!!!' | 184 | thirdpartyTips: '本地不能模拟,请结合自己业务进行模拟!!!' |
182 | }, | 185 | }, |
183 | documentation: { | 186 | documentation: { |
184 | documentation: '文档', | 187 | documentation: '文档', |
185 | github: 'Github 地址' | 188 | github: 'Github 地址' |
186 | }, | 189 | }, |
187 | permission: { | 190 | permission: { |
188 | addRole: '新增角色', | 191 | addRole: '新增角色', |
189 | editPermission: '编辑权限', | 192 | editPermission: '编辑权限', |
190 | roles: '你的权限', | 193 | roles: '你的权限', |
191 | switchRoles: '切换权限', | 194 | switchRoles: '切换权限', |
192 | tips: '在某些情况下,不适合使用 v-permission。例如:Element-UI 的 el-tab 或 el-table-column 以及其它动态渲染 dom 的场景。你只能通过手动设置 v-if 来实现。', | 195 | tips: '在某些情况下,不适合使用 v-permission。例如:Element-UI 的 el-tab 或 el-table-column 以及其它动态渲染 dom 的场景。你只能通过手动设置 v-if 来实现。', |
193 | delete: '删除', | 196 | delete: '删除', |
194 | confirm: '确定', | 197 | confirm: '确定', |
195 | cancel: '取消' | 198 | cancel: '取消' |
196 | }, | 199 | }, |
197 | guide: { | 200 | guide: { |
198 | description: '引导页对于一些第一次进入项目的人很有用,你可以简单介绍下项目的功能。本 Demo 是基于', | 201 | description: '引导页对于一些第一次进入项目的人很有用,你可以简单介绍下项目的功能。本 Demo 是基于', |
199 | button: '打开引导' | 202 | button: '打开引导' |
200 | }, | 203 | }, |
201 | components: { | 204 | components: { |
202 | documentation: '文档', | 205 | documentation: '文档', |
203 | tinymceTips: '富文本是管理后台一个核心的功能,但同时又是一个有很多坑的地方。在选择富文本的过程中我也走了不少的弯路,市面上常见的富文本都基本用过了,最终权衡了一下选择了Tinymce。更详细的富文本比较和介绍见', | 206 | tinymceTips: '富文本是管理后台一个核心的功能,但同时又是一个有很多坑的地方。在选择富文本的过程中我也走了不少的弯路,市面上常见的富文本都基本用过了,最终权衡了一下选择了Tinymce。更详细的富文本比较和介绍见', |
204 | dropzoneTips: '由于我司业务有特殊需求,而且要传七牛 所以没用第三方,选择了自己封装。代码非常的简单,具体代码你可以在这里看到 @/components/Dropzone', | 207 | dropzoneTips: '由于我司业务有特殊需求,而且要传七牛 所以没用第三方,选择了自己封装。代码非常的简单,具体代码你可以在这里看到 @/components/Dropzone', |
205 | stickyTips: '当页面滚动到预设的位置会吸附在顶部', | 208 | stickyTips: '当页面滚动到预设的位置会吸附在顶部', |
206 | backToTopTips1: '页面滚动到指定位置会在右下角出现返回顶部按钮', | 209 | backToTopTips1: '页面滚动到指定位置会在右下角出现返回顶部按钮', |
207 | backToTopTips2: '可自定义按钮的样式、show/hide、出现的高度、返回的位置 如需文字提示,可在外部使用Element的el-tooltip元素', | 210 | backToTopTips2: '可自定义按钮的样式、show/hide、出现的高度、返回的位置 如需文字提示,可在外部使用Element的el-tooltip元素', |
208 | imageUploadTips: '由于我在使用时它只有vue@1版本,而且和mockjs不兼容,所以自己改造了一下,如果大家要使用的话,优先还是使用官方版本。' | 211 | imageUploadTips: '由于我在使用时它只有vue@1版本,而且和mockjs不兼容,所以自己改造了一下,如果大家要使用的话,优先还是使用官方版本。' |
209 | }, | 212 | }, |
210 | table: { | 213 | table: { |
211 | dynamicTips1: '固定表头, 按照表头顺序排序', | 214 | dynamicTips1: '固定表头, 按照表头顺序排序', |
212 | dynamicTips2: '不固定表头, 按照点击顺序排序', | 215 | dynamicTips2: '不固定表头, 按照点击顺序排序', |
213 | dragTips1: '默认顺序', | 216 | dragTips1: '默认顺序', |
214 | dragTips2: '拖拽后顺序', | 217 | dragTips2: '拖拽后顺序', |
215 | title: '标题', | 218 | title: '标题', |
216 | importance: '重要性', | 219 | importance: '重要性', |
217 | type: '类型', | 220 | type: '类型', |
218 | remark: '点评', | 221 | remark: '点评', |
219 | search: '搜索', | 222 | search: '搜索', |
220 | add: '添加', | 223 | add: '添加', |
221 | export: '导出', | 224 | export: '导出', |
222 | reviewer: '审核人', | 225 | reviewer: '审核人', |
223 | id: '序号', | 226 | id: '序号', |
224 | date: '时间', | 227 | date: '时间', |
225 | author: '作者', | 228 | author: '作者', |
226 | readings: '阅读数', | 229 | readings: '阅读数', |
227 | status: '状态', | 230 | status: '状态', |
228 | actions: '操作', | 231 | actions: '操作', |
229 | edit: '编辑', | 232 | edit: '编辑', |
230 | publish: '发布', | 233 | publish: '发布', |
231 | draft: '草稿', | 234 | draft: '草稿', |
232 | delete: '删除', | 235 | delete: '删除', |
233 | cancel: '取 消', | 236 | cancel: '取 消', |
234 | confirm: '确 定' | 237 | confirm: '确 定' |
235 | }, | 238 | }, |
236 | example: { | 239 | example: { |
237 | warning: '创建和编辑页面是不能被 keep-alive 缓存的,因为keep-alive 的 include 目前不支持根据路由来缓存,所以目前都是基于 component name 来进行缓存的。如果你想类似的实现缓存效果,可以使用 localStorage 等浏览器缓存方案。或者不要使用 keep-alive 的 include,直接缓存所有页面。详情见' | 240 | warning: '创建和编辑页面是不能被 keep-alive 缓存的,因为keep-alive 的 include 目前不支持根据路由来缓存,所以目前都是基于 component name 来进行缓存的。如果你想类似的实现缓存效果,可以使用 localStorage 等浏览器缓存方案。或者不要使用 keep-alive 的 include,直接缓存所有页面。详情见' |
238 | }, | 241 | }, |
239 | errorLog: { | 242 | errorLog: { |
240 | tips: '请点击右上角bug小图标', | 243 | tips: '请点击右上角bug小图标', |
241 | description: '现在的管理后台基本都是spa的形式了,它增强了用户体验,但同时也会增加页面出问题的可能性,可能一个小小的疏忽就导致整个页面的死锁。好在 Vue 官网提供了一个方法来捕获处理异常,你可以在其中进行错误处理或者异常上报。', | 244 | description: '现在的管理后台基本都是spa的形式了,它增强了用户体验,但同时也会增加页面出问题的可能性,可能一个小小的疏忽就导致整个页面的死锁。好在 Vue 官网提供了一个方法来捕获处理异常,你可以在其中进行错误处理或者异常上报。', |
242 | documentation: '文档介绍' | 245 | documentation: '文档介绍' |
243 | }, | 246 | }, |
244 | excel: { | 247 | excel: { |
245 | export: '导出', | 248 | export: '导出', |
246 | selectedExport: '导出已选择项', | 249 | selectedExport: '导出已选择项', |
247 | placeholder: '请输入文件名(默认excel-list)' | 250 | placeholder: '请输入文件名(默认excel-list)' |
248 | }, | 251 | }, |
249 | zip: { | 252 | zip: { |
250 | export: '导出', | 253 | export: '导出', |
251 | placeholder: '请输入文件名(默认file)' | 254 | placeholder: '请输入文件名(默认file)' |
252 | }, | 255 | }, |
253 | pdf: { | 256 | pdf: { |
254 | tips: '这里使用 window.print() 来实现下载pdf的功能' | 257 | tips: '这里使用 window.print() 来实现下载pdf的功能' |
255 | }, | 258 | }, |
256 | theme: { | 259 | theme: { |
257 | change: '换肤', | 260 | change: '换肤', |
258 | documentation: '换肤文档', | 261 | documentation: '换肤文档', |
259 | tips: 'Tips: 它区别于 navbar 上的 theme-pick, 是两种不同的换肤方法,各自有不同的应用场景,具体请参考文档。' | 262 | tips: 'Tips: 它区别于 navbar 上的 theme-pick, 是两种不同的换肤方法,各自有不同的应用场景,具体请参考文档。' |
260 | }, | 263 | }, |
261 | tagsView: { | 264 | tagsView: { |
262 | refresh: '刷新', | 265 | refresh: '刷新', |
263 | close: '关闭', | 266 | close: '关闭', |
264 | closeOthers: '关闭其它', | 267 | closeOthers: '关闭其它', |
265 | closeAll: '关闭所有' | 268 | closeAll: '关闭所有' |
266 | }, | 269 | }, |
267 | settings: { | 270 | settings: { |
268 | title: '系统布局配置', | 271 | title: '系统布局配置', |
269 | theme: '主题色', | 272 | theme: '主题色', |
270 | tagsView: '开启 Tags-View', | 273 | tagsView: '开启 Tags-View', |
271 | fixedHeader: '固定 Header', | 274 | fixedHeader: '固定 Header', |
272 | sidebarLogo: '侧边栏 Logo' | 275 | sidebarLogo: '侧边栏 Logo' |
273 | } | 276 | } |
274 | } | 277 | } |
275 | 278 |
src/router/modules/prod.js
1 | /** When your routing table is too long, you can split it into small modules**/ | 1 | /** When your routing table is too long, you can split it into small modules**/ |
2 | 2 | ||
3 | import Layout from '@/layout' | 3 | import Layout from '@/layout' |
4 | 4 | ||
5 | const prodRouter = { | 5 | const prodRouter = { |
6 | path: '/prod', | 6 | path: '/prod', |
7 | component: Layout, | 7 | component: Layout, |
8 | redirect: '/prod/page', | 8 | redirect: '/prod/page', |
9 | alwaysShow: true, // will always show the root menu | 9 | alwaysShow: true, // will always show the root menu |
10 | name: 'Prod', | 10 | name: 'Prod', |
11 | meta: { | 11 | meta: { |
12 | title: 'prods.prod_menu', // 会自动被i18n替换 | 12 | title: 'prods.prod_menu', // 会自动被i18n替换 |
13 | icon: 'star', | 13 | icon: 'star', |
14 | roles: ['admin', 'assistant', 'runner', 'shoper'] // you can set roles in root nav | 14 | roles: ['admin', 'assistant', 'runner', 'shoper'] // you can set roles in root nav |
15 | }, | 15 | }, |
16 | children: [{ | 16 | children: [{ |
17 | path: 'list', | 17 | path: 'list', |
18 | component: () => import('@/views/prod/list'), | 18 | component: () => import('@/views/prod/list'), |
19 | name: 'prodList', | 19 | name: 'ProdList', |
20 | meta: { | 20 | meta: { |
21 | title: 'prods.prodlist', | 21 | title: 'prods.prodlist', |
22 | roles: ['admin', 'assistant', 'shoper', 'runner'] | 22 | roles: ['admin', 'assistant', 'shoper', 'runner'] |
23 | } | 23 | } |
24 | }, { | ||
25 | path: 'edit/:pid(\\d+)', | ||
26 | component: () => import('@/views/prod/edit'), | ||
27 | name: 'ProdEdit', | ||
28 | meta: { | ||
29 | title: 'prods.prodedit', | ||
30 | noCache: true, | ||
31 | activeMenu: '/prod/list' | ||
32 | }, | ||
33 | hidden: true | ||
34 | }, { | ||
35 | path: 'create/:fid(\\d+)', | ||
36 | component: () => import('@/views/prod/create'), | ||
37 | name: 'ProdCreate', | ||
38 | meta: { | ||
39 | title: 'prods.prodcreate', | ||
40 | noCache: true, | ||
41 | activeMenu: '/prod/list' | ||
42 | }, | ||
43 | hidden: true | ||
24 | }] | 44 | }] |
25 | } | 45 | } |
26 | 46 | ||
27 | export default prodRouter | 47 | export default prodRouter |
28 | 48 |
src/router/modules/sites.js
1 | import Layout from '@/layout' | 1 | import Layout from '@/layout' |
2 | 2 | ||
3 | const sitesRouter = { | 3 | const sitesRouter = { |
4 | path: '/sites', | 4 | path: '/sites', |
5 | component: Layout, | 5 | component: Layout, |
6 | redirect: '/site/page', | 6 | redirect: '/site/page', |
7 | alwaysShow: true, // will always show the root menu | 7 | alwaysShow: true, // will always show the root menu |
8 | name: 'Site', | 8 | name: 'Site', |
9 | meta: { | 9 | meta: { |
10 | title: 'sites', | 10 | title: 'sites.sites', |
11 | icon: 'people', | 11 | icon: 'people', |
12 | roles: ['admin', 'assistant', 'runner'] // you can set roles in root nav | 12 | roles: ['admin', 'assistant', 'runner'] // you can set roles in root nav |
13 | }, | 13 | }, |
14 | children: [{ | 14 | children: [{ |
15 | path: 'sitepage', | 15 | path: 'sitepage', |
16 | component: () => import('@/views/site/list'), | 16 | component: () => import('@/views/site/list'), |
17 | name: 'SiteList', | 17 | name: 'SiteList', |
18 | meta: { | 18 | meta: { |
19 | title: '站点列表', | 19 | title: 'sites.siteList', |
20 | roles: ['admin', 'runner'] | 20 | roles: ['admin', 'runner'] |
21 | 21 | ||
22 | } | 22 | } |
23 | }] | 23 | }] |
24 | } | 24 | } |
25 | 25 | ||
26 | export default sitesRouter | 26 | export default sitesRouter |
27 | 27 |
src/store/modules/settings.js
1 | import variables from '@/styles/element-variables.scss' | 1 | import variables from '@/styles/element-variables.scss' |
2 | import defaultSettings from '@/settings' | 2 | import defaultSettings from '@/settings' |
3 | 3 | ||
4 | const { showSettings, tagsView, fixedHeader, sidebarLogo, supportPinyinSearch } = defaultSettings | 4 | const { |
5 | showSettings, | ||
6 | tagsView, | ||
7 | fixedHeader, | ||
8 | sidebarLogo, | ||
9 | supportPinyinSearch | ||
10 | } = defaultSettings | ||
5 | 11 | ||
6 | const state = { | 12 | const state = { |
7 | theme: variables.theme, | 13 | theme: variables.theme, |
8 | showSettings, | 14 | showSettings, |
9 | tagsView, | 15 | tagsView, |
10 | fixedHeader, | 16 | fixedHeader, |
11 | sidebarLogo, | 17 | sidebarLogo, |
12 | supportPinyinSearch | 18 | supportPinyinSearch |
13 | } | 19 | } |
14 | 20 | ||
15 | const mutations = { | 21 | const mutations = { |
16 | CHANGE_SETTING: (state, { key, value }) => { | 22 | CHANGE_SETTING: (state, { |
23 | key, | ||
24 | value | ||
25 | }) => { | ||
17 | if (state.hasOwnProperty(key)) { | 26 | if (state.hasOwnProperty(key)) { |
18 | state[key] = value | 27 | state[key] = value |
19 | } | 28 | } |
20 | } | 29 | } |
21 | } | 30 | } |
22 | 31 | ||
23 | const actions = { | 32 | const actions = { |
24 | changeSetting({ commit }, data) { | 33 | changeSetting({ |
34 | commit | ||
35 | }, data) { | ||
25 | commit('CHANGE_SETTING', data) | 36 | commit('CHANGE_SETTING', data) |
26 | } | 37 | } |
27 | } | 38 | } |
28 | 39 | ||
29 | export default { | 40 | export default { |
30 | namespaced: true, | 41 | namespaced: true, |
31 | state, | 42 | state, |
32 | mutations, | 43 | mutations, |
33 | actions | 44 | actions |
34 | } | 45 | } |
35 |
src/utils/request.js
1 | import axios from 'axios' | 1 | import axios from 'axios' |
2 | import qs from 'qs' | 2 | import qs from 'qs' |
3 | import { | 3 | import { |
4 | MessageBox, | 4 | MessageBox, |
5 | Message, | 5 | Message, |
6 | // Loading, | 6 | // Loading, |
7 | Notification | 7 | Notification |
8 | } from 'element-ui' | 8 | } from 'element-ui' |
9 | import store from '@/store' | 9 | import store from '@/store' |
10 | import { | 10 | import { |
11 | getToken | 11 | getToken |
12 | } from '@/utils/auth' | 12 | } from '@/utils/auth' |
13 | 13 | ||
14 | // const baseUrl = 'http://localhost/sys-glass/api'; | 14 | // const baseUrl = 'http://localhost/sys-glass/api'; |
15 | // const baseUrl = 'http://localhost:8087'; | 15 | // const baseUrl = 'http://localhost:8087'; |
16 | const baseUrl = '/dev-api' | 16 | const baseUrl = '/dev-api' |
17 | // const baseUrl = process.env.VUE_APP_BASE_API // url = base url + request url | 17 | // const baseUrl = process.env.VUE_APP_BASE_API // url = base url + request url |
18 | // create an axios instance | 18 | // create an axios instance |
19 | const service = axios.create({ | 19 | const service = axios.create({ |
20 | // baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url | 20 | // baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url |
21 | baseURL: baseUrl, // url = base url + request url | 21 | baseURL: baseUrl, // url = base url + request url |
22 | withCredentials: true, // send cookies when cross-domain requests | 22 | withCredentials: true, // send cookies when cross-domain requests |
23 | timeout: 3000 // request timeout | 23 | timeout: 3000 // request timeout |
24 | }) | 24 | }) |
25 | // let loadingInstance | 25 | // let loadingInstance |
26 | // request interceptor | 26 | // request interceptor |
27 | service.interceptors.request.use( | 27 | service.interceptors.request.use( |
28 | config => { | 28 | config => { |
29 | const token = sessionStorage.getItem('access_token') | 29 | const token = sessionStorage.getItem('access_token') |
30 | // const csrf = store.getters.csrf | 30 | // const csrf = store.getters.csrf |
31 | if (token) { | 31 | if (token) { |
32 | config.headers = { | 32 | config.headers = { |
33 | 'access-token': token, | 33 | 'access-token': token, |
34 | 'Content-Type': 'application/x-www-form-urlencoded' | 34 | 'Content-Type': 'application/x-www-form-urlencoded' |
35 | } | 35 | } |
36 | } | 36 | } |
37 | if (config.url === 'refresh') { | 37 | if (config.url === 'refresh') { |
38 | config.headers = { | 38 | config.headers = { |
39 | 'refresh-token': sessionStorage.getItem('refresh_token'), | 39 | 'refresh-token': sessionStorage.getItem('refresh_token'), |
40 | 'Content-Type': 'application/x-www-form-urlencoded' | 40 | 'Content-Type': 'application/x-www-form-urlencoded' |
41 | } | 41 | } |
42 | } | 42 | } |
43 | // let options = { | 43 | // Notification({ |
44 | // lock: true, | 44 | // type: 'success', |
45 | // fullscreen: false, | 45 | // message: baseUrl + config.url, |
46 | // text: '数据加载中……', | 46 | // title: 'request axios ', |
47 | // // background: '#FFCC00', | 47 | // showClose: true, |
48 | // spinner: 'el-icon-loading' | 48 | // duration: 3000 |
49 | // }; | 49 | // }) |
50 | const options = { | ||
51 | type: 'success', | ||
52 | message: baseUrl + config.url, | ||
53 | title: 'request axios ', | ||
54 | showClose: true, | ||
55 | duration: 3000 | ||
56 | } | ||
57 | Notification(options) | ||
58 | // loadingInstance = Loading.service(options); | 50 | // loadingInstance = Loading.service(options); |
59 | config.method === 'post' | 51 | config.method === 'post' |
60 | ? config.data = qs.stringify({ | 52 | ? config.data = qs.stringify({ |
61 | ...config.data | 53 | ...config.data |
62 | }) | 54 | }) |
63 | : config.params = { | 55 | : config.params = { |
64 | ...config.params | 56 | ...config.params |
65 | } | 57 | } |
66 | if (store.getters.token) { | 58 | if (store.getters.token) { |
67 | // let each request carry token | 59 | // let each request carry token |
68 | // ['X-Token'] is a custom headers key | 60 | // ['X-Token'] is a custom headers key |
69 | // please modify it according to the actual situation | 61 | // please modify it according to the actual situation |
70 | config.headers['X-Token'] = getToken() | 62 | config.headers['X-Token'] = getToken() |
71 | } | 63 | } |
72 | config.headers['Content-Type'] = 'application/x-www-form-urlencoded' | 64 | config.headers['Content-Type'] = 'application/x-www-form-urlencoded' |
73 | 65 | ||
74 | return config | 66 | return config |
75 | // do something before request is sent | 67 | // do something before request is sent |
76 | }, | 68 | }, |
77 | error => { | 69 | error => { |
78 | // do something with request error | ||
79 | Message({ | 70 | Message({ |
80 | message: error || 'Error', | 71 | message: error || 'Error', |
81 | type: 'error', | 72 | type: 'error', |
82 | duration: 5 * 1000 | 73 | duration: 5 * 1000 |
83 | }) | 74 | }) |
84 | console.log(error) // for debug | 75 | console.log(error) // for debug |
85 | return Promise.reject(error) | 76 | return Promise.reject(error) |
86 | } | 77 | } |
87 | ) | 78 | ) |
88 | 79 | ||
89 | // response interceptor | 80 | // response interceptor |
90 | service.interceptors.response.use( | 81 | service.interceptors.response.use( |
91 | /** | 82 | /** |
92 | * If you want to get http information such as headers or status | 83 | * If you want to get http information such as headers or status |
93 | * Please return response => response | 84 | * Please return response => response |
94 | */ | 85 | */ |
95 | 86 | ||
96 | /** | 87 | /** |
97 | * Determine the request status by custom code | 88 | * Determine the request status by custom code |
98 | * Here is just an example | 89 | * Here is just an example |
99 | * You can also judge the status by HTTP Status Code | 90 | * You can also judge the status by HTTP Status Code |
100 | */ | 91 | */ |
101 | response => { | 92 | response => { |
102 | const options = { | 93 | const options = { |
103 | type: 'error', | 94 | type: response.status == 200 ? 'success' : 'error', |
104 | message: response.status, | 95 | message: response.status, |
105 | title: 'response status value ', | 96 | title: 'response status value ', |
106 | showClose: true, | 97 | showClose: true, |
107 | duration: 1000 | 98 | duration: 1000 |
108 | } | 99 | } |
109 | Notification(options) | 100 | Notification(options) |
110 | // Notification.close() | 101 | // Notification.close() |
111 | 102 | ||
112 | // 这里根据后端提供的数据进行对应的处理 | 103 | // 这里根据后端提供的数据进行对应的处理 |
113 | console.log('response===>', response) | 104 | console.log('response===>', response) |
114 | // 定时刷新access-token | 105 | // 定时刷新access-token |
115 | // if (!response.data.value && response.data.data.message === 'token invalid') { | 106 | // if (!response.data.value && response.data.data.message === 'token invalid') { |
116 | // // 刷新token | 107 | // // 刷新token |
117 | // store.dispatch('refresh').then(response => { | 108 | // store.dispatch('refresh').then(response => { |
118 | // sessionStorage.setItem('access_token', response.data) | 109 | // sessionStorage.setItem('access_token', response.data) |
119 | // }).catch(error => { | 110 | // }).catch(error => { |
120 | // throw new Error('token刷新' + error) | 111 | // throw new Error('token刷新' + error) |
121 | // }) | 112 | // }) |
122 | // } | 113 | // } |
123 | 114 | ||
124 | const res = response.data | 115 | const res = response.data |
125 | 116 | ||
126 | // if the custom code is not 20000, it is judged as an error. | 117 | // if the custom code is not 20000, it is judged as an error. |
127 | if (res.code !== 20000) { | 118 | if (res.code !== 20000) { |
128 | Message({ | 119 | Message({ |
129 | message: res.message || 'Error', | 120 | message: res.message || 'Error', |
130 | type: 'error', | 121 | type: 'error', |
131 | duration: 5 * 1000 | 122 | duration: 5 * 1000 |
132 | }) | 123 | }) |
133 | 124 | ||
134 | // 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired; | 125 | // 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired; |
135 | if (res.code === 50008 || res.code === 50012 || res.code === 50014) { | 126 | if (res.code === 50008 || res.code === 50012 || res.code === 50014) { |
136 | // to re-login | 127 | // to re-login |
137 | MessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', { | 128 | MessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', { |
138 | confirmButtonText: 'Re-Login', | 129 | confirmButtonText: 'Re-Login', |
139 | cancelButtonText: 'Cancel', | 130 | cancelButtonText: 'Cancel', |
140 | type: 'warning' | 131 | type: 'warning' |
141 | }).then(() => { | 132 | }).then(() => { |
142 | store.dispatch('user/resetToken').then(() => { | 133 | store.dispatch('user/resetToken').then(() => { |
143 | location.reload() | 134 | location.reload() |
144 | }) | 135 | }) |
145 | }) | 136 | }) |
146 | } | 137 | } |
147 | return Promise.reject(new Error(res.message || 'Error')) | 138 | return Promise.reject(new Error(res.message || 'Error')) |
148 | } else { | 139 | } else { |
149 | return res | 140 | return res |
150 | } | 141 | } |
151 | }, | 142 | }, |
152 | error => { | 143 | error => { |
153 | console.log('error', error) | 144 | console.log('error', error) |
154 | // console.log(JSON.stringify(error)); | 145 | // console.log(JSON.stringify(error)); |
155 | // 500的状态也应该处理一下 | 146 | // 500的状态也应该处理一下 |
156 | // 401-403的状态也应该处理一下 | 147 | // 401-403的状态也应该处理一下 |
157 | const text = JSON.parse(JSON.stringify(error)).response.status === 404 | 148 | const text = JSON.parse(JSON.stringify(error)).response.status === 404 |
158 | ? '404' | 149 | ? '404' |
159 | : '网络异常,请重试' | 150 | : '网络异常,请重试' |
160 | Message({ | 151 | Message({ |
161 | message: text || 'Error', | 152 | message: text || 'Error', |
162 | type: 'error', | 153 | type: 'error', |
163 | duration: 5 * 1000 | 154 | duration: 5 * 1000 |
164 | }) | 155 | }) |
165 | 156 | ||
166 | return Promise.reject(error) | 157 | return Promise.reject(error) |
167 | } | 158 | } |
168 | ) | 159 | ) |
169 | 160 | ||
170 | // 假设你想移除拦截器 | 161 | // 假设你想移除拦截器 |
171 | // axios.interceptors.request.eject(service); | 162 | // axios.interceptors.request.eject(service); |
172 | 163 | ||
173 | export default service | 164 | export default service |
174 | 165 |
src/views/example/list.vue
1 | <template> | 1 | <template> |
2 | <div class="app-container"> | 2 | <div class="app-container"> |
3 | <el-table v-loading="listLoading" :data="list" border fit highlight-current-row style="width: 100%"> | 3 | <el-table |
4 | <el-table-column align="center" label="ID" width="80"> | 4 | v-loading="listLoading" |
5 | :data="list" | ||
6 | border | ||
7 | fit | ||
8 | highlight-current-row | ||
9 | style="width: 100%" | ||
10 | > | ||
11 | <el-table-column | ||
12 | align="center" | ||
13 | label="ID" | ||
14 | width="80" | ||
15 | > | ||
5 | <template slot-scope="scope"> | 16 | <template slot-scope="scope"> |
6 | <span>{{ scope.row.id }}</span> | 17 | <span>{{ scope.row.id }}</span> |
7 | </template> | 18 | </template> |
8 | </el-table-column> | 19 | </el-table-column> |
9 | 20 | ||
10 | <el-table-column width="180px" align="center" label="Date"> | 21 | <el-table-column |
22 | width="180px" | ||
23 | align="center" | ||
24 | label="Date" | ||
25 | > | ||
11 | <template slot-scope="scope"> | 26 | <template slot-scope="scope"> |
12 | <span>{{ scope.row.timestamp | parseTime('{y}-{m}-{d} {h}:{i}') }}</span> | 27 | <span>{{ scope.row.timestamp | parseTime('{y}-{m}-{d} {h}:{i}') }}</span> |
13 | </template> | 28 | </template> |
14 | </el-table-column> | 29 | </el-table-column> |
15 | 30 | ||
16 | <el-table-column width="120px" align="center" label="Author"> | 31 | <el-table-column |
32 | width="120px" | ||
33 | align="center" | ||
34 | label="Author" | ||
35 | > | ||
17 | <template slot-scope="scope"> | 36 | <template slot-scope="scope"> |
18 | <span>{{ scope.row.author }}</span> | 37 | <span>{{ scope.row.author }}</span> |
19 | </template> | 38 | </template> |
20 | </el-table-column> | 39 | </el-table-column> |
21 | 40 | ||
22 | <el-table-column width="100px" label="Importance"> | 41 | <el-table-column |
42 | width="100px" | ||
43 | label="Importance" | ||
44 | > | ||
23 | <template slot-scope="scope"> | 45 | <template slot-scope="scope"> |
24 | <svg-icon v-for="n in +scope.row.importance" :key="n" icon-class="star" class="meta-item__icon" /> | 46 | <svg-icon |
47 | v-for="n in +scope.row.importance" | ||
48 | :key="n" | ||
49 | icon-class="star" | ||
50 | class="meta-item__icon" | ||
51 | /> | ||
25 | </template> | 52 | </template> |
26 | </el-table-column> | 53 | </el-table-column> |
27 | 54 | ||
28 | <el-table-column class-name="status-col" label="Status" width="110"> | 55 | <el-table-column |
56 | class-name="status-col" | ||
57 | label="Status" | ||
58 | width="110" | ||
59 | > | ||
29 | <template slot-scope="{row}"> | 60 | <template slot-scope="{row}"> |
30 | <el-tag :type="row.status | statusFilter"> | 61 | <el-tag :type="row.status | statusFilter"> |
31 | {{ row.status }} | 62 | {{ row.status }} |
32 | </el-tag> | 63 | </el-tag> |
33 | </template> | 64 | </template> |
34 | </el-table-column> | 65 | </el-table-column> |
35 | 66 | ||
36 | <el-table-column min-width="300px" label="Title"> | 67 | <el-table-column |
68 | min-width="300px" | ||
69 | label="Title" | ||
70 | > | ||
37 | <template slot-scope="{row}"> | 71 | <template slot-scope="{row}"> |
38 | <router-link :to="'/example/edit/'+row.id" class="link-type"> | 72 | <router-link |
73 | :to="'/example/edit/'+row.id" | ||
74 | class="link-type" | ||
75 | > | ||
39 | <span>{{ row.title }}</span> | 76 | <span>{{ row.title }}</span> |
40 | </router-link> | 77 | </router-link> |
41 | </template> | 78 | </template> |
42 | </el-table-column> | 79 | </el-table-column> |
43 | 80 | ||
44 | <el-table-column align="center" label="Actions" width="120"> | 81 | <el-table-column |
82 | align="center" | ||
83 | label="Actions" | ||
84 | width="120" | ||
85 | > | ||
45 | <template slot-scope="scope"> | 86 | <template slot-scope="scope"> |
46 | <router-link :to="'/example/edit/'+scope.row.id"> | 87 | <router-link :to="'/example/edit/'+scope.row.id"> |
47 | <el-button type="primary" size="small" icon="el-icon-edit"> | 88 | <el-button |
89 | type="primary" | ||
90 | size="small" | ||
91 | icon="el-icon-edit" | ||
92 | > | ||
48 | Edit | 93 | Edit |
49 | </el-button> | 94 | </el-button> |
50 | </router-link> | 95 | </router-link> |
51 | </template> | 96 | </template> |
52 | </el-table-column> | 97 | </el-table-column> |
53 | </el-table> | 98 | </el-table> |
54 | 99 | ||
55 | <pagination v-show="total>0" :total="total" :page.sync="listQuery.page" :limit.sync="listQuery.limit" @pagination="getList" /> | 100 | <pagination |
101 | v-show="total>0" | ||
102 | :total="total" | ||
103 | :page.sync="listQuery.page" | ||
104 | :limit.sync="listQuery.limit" | ||
105 | @pagination="getList" | ||
106 | /> | ||
56 | </div> | 107 | </div> |
57 | </template> | 108 | </template> |
58 | 109 | ||
59 | <script> | 110 | <script> |
60 | import { fetchList } from '@/api/article' | 111 | import { fetchList } from '@/api/article' |
61 | import Pagination from '@/components/Pagination' // Secondary package based on el-pagination | 112 | import Pagination from '@/components/Pagination' // Secondary package based on el-pagination |
62 | 113 | ||
63 | export default { | 114 | export default { |
64 | name: 'ArticleList', | 115 | name: 'ArticleList', |
65 | components: { Pagination }, | 116 | components: { Pagination }, |
66 | filters: { | 117 | filters: { |
67 | statusFilter(status) { | 118 | statusFilter(status) { |
68 | const statusMap = { | 119 | const statusMap = { |
69 | published: 'success', | 120 | published: 'success', |
70 | draft: 'info', | 121 | draft: 'info', |
71 | deleted: 'danger' | 122 | deleted: 'danger' |
72 | } | 123 | } |
73 | return statusMap[status] | 124 | return statusMap[status] |
74 | } | 125 | } |
75 | }, | 126 | }, |
76 | data() { | 127 | data() { |
77 | return { | 128 | return { |
78 | list: null, | 129 | list: null, |
79 | total: 0, | 130 | total: 0, |
80 | listLoading: true, | 131 | listLoading: true, |
81 | listQuery: { | 132 | listQuery: { |
82 | page: 1, | 133 | page: 1, |
83 | limit: 20 | 134 | limit: 20 |
84 | } | 135 | } |
85 | } | 136 | } |
86 | }, | 137 | }, |
87 | created() { | 138 | created() { |
88 | this.getList() | 139 | this.getList() |
89 | }, | 140 | }, |
90 | methods: { | 141 | methods: { |
91 | getList() { | 142 | getList() { |
92 | this.listLoading = true | 143 | this.listLoading = true |
93 | fetchList(this.listQuery).then(response => { | 144 | fetchList(this.listQuery).then(response => { |
94 | this.list = response.data.items | 145 | this.list = response.data.items |
95 | this.total = response.data.total | 146 | this.total = response.data.total |
96 | this.listLoading = false | 147 | this.listLoading = false |
97 | }) | 148 | }) |
98 | } | 149 | } |
99 | } | 150 | } |
100 | } | 151 | } |
101 | </script> | 152 | </script> |
102 | 153 | ||
103 | <style scoped> | 154 | <style scoped> |
104 | .edit-input { | 155 | .edit-input { |
105 | padding-right: 100px; | 156 | padding-right: 100px; |
106 | } | 157 | } |
107 | .cancel-btn { | 158 | .cancel-btn { |
108 | position: absolute; | 159 | position: absolute; |
109 | right: 15px; | 160 | right: 15px; |
110 | top: 10px; | 161 | top: 10px; |
111 | } | 162 | } |
112 | </style> | 163 | </style> |
113 | 164 |
src/views/prod/components/Dropdown/Comment.vue
File was created | 1 | <template> | |
2 | <el-dropdown :show-timeout="100" trigger="click"> | ||
3 | <el-button plain> | ||
4 | {{ !comment_disabled?'Comment: opened':'Comment: closed' }} | ||
5 | <i class="el-icon-caret-bottom el-icon--right" /> | ||
6 | </el-button> | ||
7 | <el-dropdown-menu slot="dropdown" class="no-padding"> | ||
8 | <el-dropdown-item> | ||
9 | <el-radio-group v-model="comment_disabled" style="padding: 10px;"> | ||
10 | <el-radio :label="true"> | ||
11 | Close comment | ||
12 | </el-radio> | ||
13 | <el-radio :label="false"> | ||
14 | Open comment | ||
15 | </el-radio> | ||
16 | </el-radio-group> | ||
17 | </el-dropdown-item> | ||
18 | </el-dropdown-menu> | ||
19 | </el-dropdown> | ||
20 | </template> | ||
21 | |||
22 | <script> | ||
23 | export default { | ||
24 | props: { | ||
25 | value: { | ||
26 | type: Boolean, | ||
27 | default: false | ||
28 | } | ||
29 | }, | ||
30 | computed: { | ||
31 | comment_disabled: { | ||
32 | get() { | ||
33 | return this.value | ||
34 | }, | ||
35 | set(val) { | ||
36 | this.$emit('input', val) | ||
37 | } | ||
38 | } | ||
39 | } | ||
40 | } | ||
41 | </script> | ||
42 |
src/views/prod/components/Dropdown/Platform.vue
File was created | 1 | <template> | |
2 | <el-dropdown :hide-on-click="false" :show-timeout="100" trigger="click"> | ||
3 | <el-button plain> | ||
4 | Platfroms({{ platforms.length }}) | ||
5 | <i class="el-icon-caret-bottom el-icon--right" /> | ||
6 | </el-button> | ||
7 | <el-dropdown-menu slot="dropdown" class="no-border"> | ||
8 | <el-checkbox-group v-model="platforms" style="padding: 5px 15px;"> | ||
9 | <el-checkbox v-for="item in platformsOptions" :key="item.key" :label="item.key"> | ||
10 | {{ item.name }} | ||
11 | </el-checkbox> | ||
12 | </el-checkbox-group> | ||
13 | </el-dropdown-menu> | ||
14 | </el-dropdown> | ||
15 | </template> | ||
16 | |||
17 | <script> | ||
18 | export default { | ||
19 | props: { | ||
20 | value: { | ||
21 | required: true, | ||
22 | default: () => [], | ||
23 | type: Array | ||
24 | } | ||
25 | }, | ||
26 | data() { | ||
27 | return { | ||
28 | platformsOptions: [ | ||
29 | { key: 'a-platform', name: 'a-platform' }, | ||
30 | { key: 'b-platform', name: 'b-platform' }, | ||
31 | { key: 'c-platform', name: 'c-platform' } | ||
32 | ] | ||
33 | } | ||
34 | }, | ||
35 | computed: { | ||
36 | platforms: { | ||
37 | get() { | ||
38 | return this.value | ||
39 | }, | ||
40 | set(val) { | ||
41 | this.$emit('input', val) | ||
42 | } | ||
43 | } | ||
44 | } | ||
45 | } | ||
46 | </script> | ||
47 |
src/views/prod/components/Dropdown/SourceUrl.vue
File was created | 1 | <template> | |
2 | <el-dropdown :show-timeout="100" trigger="click"> | ||
3 | <el-button plain> | ||
4 | Link | ||
5 | <i class="el-icon-caret-bottom el-icon--right" /> | ||
6 | </el-button> | ||
7 | <el-dropdown-menu slot="dropdown" class="no-padding no-border" style="width:400px"> | ||
8 | <el-form-item label-width="0px" style="margin-bottom: 0px" prop="source_uri"> | ||
9 | <el-input v-model="source_uri" placeholder="Please enter the content"> | ||
10 | <template slot="prepend"> | ||
11 | URL | ||
12 | </template> | ||
13 | </el-input> | ||
14 | </el-form-item> | ||
15 | </el-dropdown-menu> | ||
16 | </el-dropdown> | ||
17 | </template> | ||
18 | |||
19 | <script> | ||
20 | export default { | ||
21 | props: { | ||
22 | value: { | ||
23 | type: String, | ||
24 | default: '' | ||
25 | } | ||
26 | }, | ||
27 | computed: { | ||
28 | source_uri: { | ||
29 | get() { | ||
30 | return this.value | ||
31 | }, | ||
32 | set(val) { | ||
33 | this.$emit('input', val) | ||
34 | } | ||
35 | } | ||
36 | } | ||
37 | } | ||
38 | </script> | ||
39 |
src/views/prod/components/Dropdown/index.js
File was created | 1 | export { default as CommentDropdown } from './Comment' | |
2 | export { default as PlatformDropdown } from './Platform' | ||
3 | export { default as SourceUrlDropdown } from './SourceUrl' | ||
4 |
src/views/prod/components/ProdDetail.vue
File was created | 1 | <template> | |
2 | <div class="createPost-container"> | ||
3 | <el-form | ||
4 | ref="postForm" | ||
5 | :model="postForm" | ||
6 | :rules="rules" | ||
7 | class="form-container" | ||
8 | > | ||
9 | <sticky | ||
10 | :z-index="10" | ||
11 | :class-name="'sub-navbar '+postForm.status" | ||
12 | > | ||
13 | <CommentDropdown v-model="postForm.comment_disabled" /> | ||
14 | <PlatformDropdown v-model="postForm.platforms" /> | ||
15 | <SourceUrlDropdown v-model="postForm.source_uri" /> | ||
16 | <el-button | ||
17 | v-loading="loading" | ||
18 | style="margin-left: 10px;" | ||
19 | type="success" | ||
20 | @click="submitForm" | ||
21 | > | ||
22 | Publish | ||
23 | </el-button> | ||
24 | <el-button | ||
25 | v-loading="loading" | ||
26 | type="warning" | ||
27 | @click="draftForm" | ||
28 | > | ||
29 | Draft | ||
30 | </el-button> | ||
31 | </sticky> | ||
32 | |||
33 | <div class="createPost-main-container"> | ||
34 | <el-row> | ||
35 | <!-- <Warning /> --> | ||
36 | <el-col :span="24"> | ||
37 | <el-form-item | ||
38 | style="margin-bottom: 40px;" | ||
39 | prop="title" | ||
40 | > | ||
41 | <MDinput | ||
42 | v-model="postForm.title" | ||
43 | :maxlength="100" | ||
44 | name="name" | ||
45 | required | ||
46 | > | ||
47 | Title | ||
48 | </MDinput> | ||
49 | </el-form-item> | ||
50 | |||
51 | <div class="postInfo-container"> | ||
52 | <el-row> | ||
53 | <el-col :span="8"> | ||
54 | <el-form-item | ||
55 | label-width="60px" | ||
56 | label="shoper:" | ||
57 | class="postInfo-container-item" | ||
58 | > | ||
59 | <el-select | ||
60 | v-model="postForm.shoper" | ||
61 | :remote-method="getRemoteUserList" | ||
62 | filterable | ||
63 | default-first-option | ||
64 | remote | ||
65 | placeholder="Search user" | ||
66 | > | ||
67 | <el-option | ||
68 | v-for="(item,index) in userListOptions" | ||
69 | :key="item+index" | ||
70 | :label="item" | ||
71 | :value="item" | ||
72 | /> | ||
73 | </el-select> | ||
74 | </el-form-item> | ||
75 | </el-col> | ||
76 | |||
77 | <el-col :span="10"> | ||
78 | <el-form-item | ||
79 | label-width="120px" | ||
80 | label="Publish Time:" | ||
81 | class="postInfo-container-item" | ||
82 | > | ||
83 | <el-date-picker | ||
84 | v-model="displayTime" | ||
85 | type="datetime" | ||
86 | format="yyyy-MM-dd HH:mm:ss" | ||
87 | placeholder="Select date and time" | ||
88 | /> | ||
89 | </el-form-item> | ||
90 | </el-col> | ||
91 | |||
92 | <el-col :span="6"> | ||
93 | <el-form-item | ||
94 | label-width="90px" | ||
95 | label="Importance:" | ||
96 | class="postInfo-container-item" | ||
97 | > | ||
98 | <el-rate | ||
99 | v-model="postForm.importance" | ||
100 | :max="3" | ||
101 | :colors="['#99A9BF', '#F7BA2A', '#FF9900']" | ||
102 | :low-threshold="1" | ||
103 | :high-threshold="3" | ||
104 | style="display:inline-block" | ||
105 | /> | ||
106 | </el-form-item> | ||
107 | </el-col> | ||
108 | </el-row> | ||
109 | </div> | ||
110 | </el-col> | ||
111 | </el-row> | ||
112 | |||
113 | <el-form-item | ||
114 | style="margin-bottom: 40px;" | ||
115 | label-width="70px" | ||
116 | label="Summary:" | ||
117 | > | ||
118 | <el-input | ||
119 | v-model="postForm.content_short" | ||
120 | :rows="1" | ||
121 | type="textarea" | ||
122 | class="article-textarea" | ||
123 | autosize | ||
124 | placeholder="Please enter the content" | ||
125 | /> | ||
126 | <span | ||
127 | v-show="contentShortLength" | ||
128 | class="word-counter" | ||
129 | >{{ contentShortLength }}words</span> | ||
130 | </el-form-item> | ||
131 | |||
132 | <el-form-item | ||
133 | prop="content" | ||
134 | style="margin-bottom: 30px;" | ||
135 | > | ||
136 | <Tinymce | ||
137 | ref="editor" | ||
138 | v-model="postForm.content" | ||
139 | :height="400" | ||
140 | /> | ||
141 | </el-form-item> | ||
142 | |||
143 | <el-form-item | ||
144 | prop="image_uri" | ||
145 | style="margin-bottom: 30px;" | ||
146 | > | ||
147 | <Upload v-model="postForm.image_uri" /> | ||
148 | </el-form-item> | ||
149 | </div> | ||
150 | </el-form> | ||
151 | </div> | ||
152 | </template> | ||
153 | |||
154 | <script> | ||
155 | import Tinymce from '@/components/Tinymce' | ||
156 | import Upload from '@/components/Upload/SingleImage3' | ||
157 | import MDinput from '@/components/MDinput' | ||
158 | import Sticky from '@/components/Sticky' // 粘性header组件 | ||
159 | import { validURL } from '@/utils/validate' | ||
160 | import { fetchProd } from '@/api/prod' | ||
161 | import { searchUser } from '@/api/remote-search' | ||
162 | // import Warning from './Warning' | ||
163 | import { | ||
164 | CommentDropdown, | ||
165 | PlatformDropdown, | ||
166 | SourceUrlDropdown | ||
167 | } from './Dropdown' | ||
168 | |||
169 | const defaultForm = { | ||
170 | status: 'draft', | ||
171 | title: '', // 文章题目 | ||
172 | content: '', // 文章内容 | ||
173 | content_short: '', // 文章摘要 | ||
174 | source_uri: '', // 文章外链 | ||
175 | image_uri: '', // 文章图片 | ||
176 | display_time: undefined, // 前台展示时间 | ||
177 | id: undefined, | ||
178 | platforms: ['a-platform'], | ||
179 | comment_disabled: false, | ||
180 | importance: 0 | ||
181 | } | ||
182 | |||
183 | export default { | ||
184 | name: 'ProdDetail', | ||
185 | components: { | ||
186 | Tinymce, | ||
187 | MDinput, | ||
188 | Upload, | ||
189 | Sticky, | ||
190 | // Warning, | ||
191 | CommentDropdown, | ||
192 | PlatformDropdown, | ||
193 | SourceUrlDropdown | ||
194 | }, | ||
195 | props: { | ||
196 | isEdit: { | ||
197 | type: Boolean, | ||
198 | default: false | ||
199 | } | ||
200 | }, | ||
201 | data() { | ||
202 | const validateRequire = (rule, value, callback) => { | ||
203 | if (value === '') { | ||
204 | this.$message({ | ||
205 | message: rule.field + '为必传项', | ||
206 | type: 'error' | ||
207 | }) | ||
208 | callback(new Error(rule.field + '为必传项')) | ||
209 | } else { | ||
210 | callback() | ||
211 | } | ||
212 | } | ||
213 | const validateSourceUri = (rule, value, callback) => { | ||
214 | if (value) { | ||
215 | if (validURL(value)) { | ||
216 | callback() | ||
217 | } else { | ||
218 | this.$message({ | ||
219 | message: '外链url填写不正确', | ||
220 | type: 'error' | ||
221 | }) | ||
222 | callback(new Error('外链url填写不正确')) | ||
223 | } | ||
224 | } else { | ||
225 | callback() | ||
226 | } | ||
227 | } | ||
228 | return { | ||
229 | postForm: Object.assign({}, defaultForm), | ||
230 | loading: false, | ||
231 | userListOptions: [], | ||
232 | rules: { | ||
233 | image_uri: [{ validator: validateRequire }], | ||
234 | title: [{ validator: validateRequire }], | ||
235 | content: [{ validator: validateRequire }], | ||
236 | source_uri: [{ validator: validateSourceUri, trigger: 'blur' }] | ||
237 | }, | ||
238 | tempRoute: {} | ||
239 | } | ||
240 | }, | ||
241 | computed: { | ||
242 | contentShortLength() { | ||
243 | return this.postForm.content_short.length | ||
244 | }, | ||
245 | lang() { | ||
246 | return this.$store.getters.language | ||
247 | }, | ||
248 | displayTime: { | ||
249 | // set and get is useful when the data | ||
250 | // returned by the back end api is different from the front end | ||
251 | // back end return => "2013-06-25 06:59:25" | ||
252 | // front end need timestamp => 1372114765000 | ||
253 | get() { | ||
254 | return +new Date(this.postForm.display_time) | ||
255 | }, | ||
256 | set(val) { | ||
257 | this.postForm.display_time = new Date(val) | ||
258 | } | ||
259 | } | ||
260 | }, | ||
261 | created() { | ||
262 | if (this.isEdit) { | ||
263 | const pid = this.$route.params && this.$route.params.pid | ||
264 | this.fetchData(pid) | ||
265 | } | ||
266 | |||
267 | // Why need to make a copy of this.$route here? | ||
268 | // Because if you enter this page and quickly switch tag, may be in the execution of the setTagsViewTitle function, this.$route is no longer pointing to the current page | ||
269 | // https://github.com/PanJiaChen/vue-element-admin/issues/1221 | ||
270 | this.tempRoute = Object.assign({}, this.$route) | ||
271 | }, | ||
272 | methods: { | ||
273 | fetchData(pid) { | ||
274 | fetchProd(pid) | ||
275 | .then(response => { | ||
276 | this.postForm = response.data | ||
277 | |||
278 | // just for test | ||
279 | this.postForm.title += ` prod pId:${this.postForm.pid}` | ||
280 | this.postForm.content_short += ` prod Id:${this.postForm.pid}` | ||
281 | |||
282 | // set tagsview title | ||
283 | this.setTagsViewTitle() | ||
284 | |||
285 | // set page title | ||
286 | this.setPageTitle() | ||
287 | }) | ||
288 | .catch(err => { | ||
289 | console.log(err) | ||
290 | }) | ||
291 | }, | ||
292 | setTagsViewTitle() { | ||
293 | const title = this.lang === 'zh' ? '编辑文章' : 'Edit Article' | ||
294 | const route = Object.assign({}, this.tempRoute, { | ||
295 | title: `${title}-${this.postForm.pid}` | ||
296 | }) | ||
297 | this.$store.dispatch('tagsView/updateVisitedView', route) | ||
298 | }, | ||
299 | setPageTitle() { | ||
300 | const title = 'Edit Article' | ||
301 | document.title = `${title} - ${this.postForm.pid}` | ||
302 | }, | ||
303 | submitForm() { | ||
304 | console.log('this.postForm', this.postForm) | ||
305 | this.$refs.postForm.validate(valid => { | ||
306 | if (valid) { | ||
307 | this.loading = true | ||
308 | this.$notify({ | ||
309 | title: '成功', | ||
310 | message: '发布文章成功', | ||
311 | type: 'success', | ||
312 | duration: 2000 | ||
313 | }) | ||
314 | this.postForm.status = 'published' | ||
315 | this.loading = false | ||
316 | } else { | ||
317 | console.log('error submit!!') | ||
318 | return false | ||
319 | } | ||
320 | }) | ||
321 | }, | ||
322 | draftForm() { | ||
323 | if ( | ||
324 | this.postForm.content.length === 0 || | ||
325 | this.postForm.title.length === 0 | ||
326 | ) { | ||
327 | this.$message({ | ||
328 | message: '请填写必要的标题和内容', | ||
329 | type: 'warning' | ||
330 | }) | ||
331 | return | ||
332 | } | ||
333 | this.$message({ | ||
334 | message: '保存成功', | ||
335 | type: 'success', | ||
336 | showClose: true, | ||
337 | duration: 1000 | ||
338 | }) | ||
339 | this.postForm.status = 'draft' | ||
340 | }, | ||
341 | getRemoteUserList(query) { | ||
342 | searchUser(query).then(response => { | ||
343 | if (!response.data.items) return | ||
344 | this.userListOptions = response.data.items.map(v => v.name) | ||
345 | }) | ||
346 | } | ||
347 | } | ||
348 | } | ||
349 | </script> | ||
350 | |||
351 | <style lang="scss" scoped> | ||
352 | @import "~@/styles/mixin.scss"; | ||
353 | |||
354 | .createPost-container { | ||
355 | position: relative; | ||
356 | |||
357 | .createPost-main-container { | ||
358 | padding: 40px 45px 20px 50px; | ||
359 | |||
360 | .postInfo-container { | ||
361 | position: relative; | ||
362 | @include clearfix; | ||
363 | margin-bottom: 10px; | ||
364 | |||
365 | .postInfo-container-item { | ||
366 | float: left; | ||
367 | } | ||
368 | } | ||
369 | } | ||
370 | |||
371 | .word-counter { | ||
372 | width: 40px; | ||
373 | position: absolute; | ||
374 | right: 10px; | ||
375 | top: 0px; | ||
376 | } | ||
377 | } | ||
378 | |||
379 | .article-textarea /deep/ { | ||
380 | textarea { | ||
381 | padding-right: 40px; | ||
382 | resize: none; | ||
383 | border: none; | ||
384 | border-radius: 0px; | ||
385 | border-bottom: 1px solid #bfcbd9; | ||
386 | } | ||
387 | } | ||
388 | </style> | ||
389 |
src/views/prod/components/Warning.vue
File was created | 1 | <template> | |
2 | <aside> | ||
3 | {{ $t('example.warning') }} | ||
4 | <a | ||
5 | href="https://panjiachen.github.io/vue-element-admin-site/guide/essentials/tags-view.html" | ||
6 | target="_blank" | ||
7 | >Document</a> | ||
8 | </aside> | ||
9 | </template> | ||
10 | |||
11 |
src/views/prod/create.vue
File was created | 1 | <template> | |
2 | <prod-detail :is-edit="false" /> | ||
3 | </template> | ||
4 | |||
5 | <script> | ||
6 | import ProdDetail from './components/ProdDetail' | ||
7 | // HTML 中的标签名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。 | ||
8 | // 这意味着当你使用 DOM 中的模板时, | ||
9 | // 使用驼峰命名法 的 prop 名需要使用其等价的短横线分隔命名方法或者全部使用小写。 | ||
10 | // 否者就会报上述错误。 | ||
11 | export default { | ||
12 | name: 'CreateForm', | ||
13 | components: { ProdDetail } | ||
14 | } | ||
15 | </script> | ||
16 | |||
17 |
src/views/prod/edit.vue
File was created | 1 | <template> | |
2 | <prod-detail :is-edit="true" /> | ||
3 | </template> | ||
4 | |||
5 | <script> | ||
6 | import ProdDetail from './components/ProdDetail' | ||
7 | |||
8 | export default { | ||
9 | name: 'EditForm', | ||
10 | components: { ProdDetail } | ||
11 | } | ||
12 | </script> | ||
13 | |||
14 |
src/views/prod/list.vue
1 | <template> | 1 | <template> |
2 | <div class="app-container"> | 2 | <div class="app-container"> |
3 | <!-- <el-header> | ||
4 | |||
5 | </el-header> --> | ||
6 | <template> | ||
7 | <router-link :to="'/prod/create/1111'"> | ||
8 | <el-button | ||
9 | type="primary" | ||
10 | size="small" | ||
11 | icon="el-icon-edit" | ||
12 | > | ||
13 | create | ||
14 | </el-button> | ||
15 | </router-link> | ||
16 | </template> | ||
3 | <el-table | 17 | <el-table |
4 | v-loading="listLoading" | 18 | v-loading="listLoading" |
5 | :data="list" | 19 | :data="list" |
6 | border | 20 | border |
7 | fit | 21 | fit |
8 | highlight-current-row | 22 | highlight-current-row |
9 | style="width: 100%" | 23 | style="width: 100%" |
10 | > | 24 | > |
11 | <el-table-column | 25 | <el-table-column |
12 | align="center" | 26 | align="center" |
13 | label="ID" | 27 | label="pid" |
14 | width="80" | ||
15 | > | 28 | > |
16 | <template slot-scope="scope"> | 29 | <template slot-scope="scope"> |
17 | <span>{{ scope.row.id }}</span> | 30 | <span>{{ scope.row.pid }}</span> |
18 | </template> | 31 | </template> |
19 | </el-table-column> | 32 | </el-table-column> |
20 | |||
21 | <el-table-column | 33 | <el-table-column |
22 | width="180px" | ||
23 | align="center" | 34 | align="center" |
24 | label="Date" | 35 | label="pname" |
25 | > | 36 | > |
26 | <template slot-scope="scope"> | 37 | <template slot-scope="scope"> |
27 | <span>{{ scope.row.timestamp | parseTime('{y}-{m}-{d} {h}:{i}') }}</span> | 38 | <span>{{ scope.row.pname }}</span> |
28 | </template> | 39 | </template> |
29 | </el-table-column> | 40 | </el-table-column> |
30 | |||
31 | <el-table-column | 41 | <el-table-column |
32 | width="120px" | ||
33 | align="center" | 42 | align="center" |
34 | label="Author" | 43 | label="参数信息" |
35 | > | 44 | > |
36 | <template slot-scope="scope"> | 45 | <template slot-scope="scope"> |
37 | <span>{{ scope.row.author }}</span> | 46 | <span>框宽{{ scope.row.prod_info_frame_width }}mm</span><br> |
47 | <span>腿长{{ scope.row.prod_info_leg_long }}mm</span><br> | ||
48 | <span>镜宽{{ scope.row.prod_info_glass_width }}mm</span><br> | ||
49 | <span>镜高{{ scope.row.prod_info_glass_height }}mm</span><br> | ||
50 | <span>鼻宽{{ scope.row.prod_info_norse_width }}mm</span><br> | ||
51 | <span>重量{{ scope.row.prod_info_weight }}g</span> | ||
38 | </template> | 52 | </template> |
39 | </el-table-column> | 53 | </el-table-column> |
40 | 54 | ||
41 | <el-table-column | 55 | <el-table-column |
42 | width="100px" | 56 | align="center" |
43 | label="Importance" | 57 | label="Date" |
44 | > | 58 | > |
45 | <template slot-scope="scope"> | 59 | <template slot-scope="scope"> |
60 | <span>{{ scope.row.timestamp | parseTime('{y}-{m}-{d} {h}:{i}') }}</span> | ||
61 | </template> | ||
62 | </el-table-column> | ||
63 | |||
64 | <el-table-column label="Importance"> | ||
65 | <template slot-scope="scope"> | ||
46 | <svg-icon | 66 | <svg-icon |
47 | v-for="n in +scope.row.importance" | 67 | v-for="n in +scope.row.importance" |
48 | :key="n" | 68 | :key="n" |
49 | icon-class="star" | 69 | icon-class="star" |
50 | class="meta-item__icon" | 70 | class="meta-item__icon" |
51 | /> | 71 | /> |
52 | </template> | 72 | </template> |
53 | </el-table-column> | 73 | </el-table-column> |
54 | 74 | ||
55 | <el-table-column | 75 | <el-table-column |
56 | class-name="status-col" | 76 | class-name="status-col" |
57 | label="Status" | 77 | label="prod_status" |
58 | width="110" | ||
59 | > | 78 | > |
60 | <template slot-scope="{row}"> | 79 | <template slot-scope="{row}"> |
61 | <el-tag :type="row.status | statusFilter"> | 80 | <el-tag :type="row.prod_status | statusFilter"> |
62 | {{ row.status }} | 81 | {{ row.prod_status }} |
63 | </el-tag> | 82 | </el-tag> |
64 | </template> | 83 | </template> |
65 | </el-table-column> | 84 | </el-table-column> |
66 | 85 | ||
67 | <el-table-column | 86 | <el-table-column |
68 | min-width="300px" | ||
69 | label="Title" | ||
70 | > | ||
71 | <template slot-scope="{row}"> | ||
72 | <router-link | ||
73 | :to="'/example/edit/'+row.id" | ||
74 | class="link-type" | ||
75 | > | ||
76 | <span>{{ row.title }}</span> | ||
77 | </router-link> | ||
78 | </template> | ||
79 | </el-table-column> | ||
80 | |||
81 | <el-table-column | ||
82 | align="center" | 87 | align="center" |
83 | label="Actions" | 88 | label="Actions" |
84 | width="120" | ||
85 | > | 89 | > |
86 | <template slot-scope="scope"> | 90 | <template slot-scope="{row}"> |
87 | <router-link :to="'/example/edit/'+scope.row.id"> | 91 | <router-link :to="'/prod/edit/'+row.pid"> |
92 | <el-button | ||
93 | type="primary" | ||
94 | size="small" | ||
95 | icon="el-icon-edit" | ||
96 | > | ||
97 | Edit1 | ||
98 | </el-button> | ||
99 | </router-link> | ||
100 | <router-link :to="'/prod/del/'+row.pid"> | ||
88 | <el-button | 101 | <el-button |
89 | type="primary" | 102 | type="primary" |
90 | size="small" | 103 | size="small" |
91 | icon="el-icon-edit" | 104 | icon="el-icon-edit" |
92 | > | 105 | > |
93 | Edit | 106 | Edit2 |
94 | </el-button> | 107 | </el-button> |
95 | </router-link> | 108 | </router-link> |
96 | </template> | 109 | </template> |
97 | </el-table-column> | 110 | </el-table-column> |
98 | </el-table> | 111 | </el-table> |
99 | 112 | ||
100 | <pagination | 113 | <pagination |
101 | v-show="total>0" | 114 | v-show="total>0" |
102 | :total="total" | 115 | :total="total" |
103 | :page.sync="listQuery.page" | 116 | :page.sync="listQuery.page" |
104 | :limit.sync="listQuery.limit" | 117 | :limit.sync="listQuery.limit" |
105 | @pagination="getList" | 118 | @pagination="getList" |
106 | /> | 119 | /> |
107 | </div> | 120 | </div> |
108 | </template> | 121 | </template> |
109 | 122 | ||
110 | <script> | 123 | <script> |
111 | import { fetchList } from '@/api/article' | 124 | import { fetchList } from '@/api/prod' |
125 | // import { Pagination } from "@/components/Pagination"; // Secondary package based on el-pagination | ||
112 | import Pagination from '@/components/Pagination' // Secondary package based on el-pagination | 126 | import Pagination from '@/components/Pagination' // Secondary package based on el-pagination |
113 | |||
114 | export default { | 127 | export default { |
115 | name: 'ArticleList', | 128 | name: 'ProdList', |
116 | components: { Pagination }, | 129 | components: { Pagination }, |
117 | filters: { | 130 | filters: { |
118 | statusFilter(status) { | 131 | statusFilter(prod_status) { |
119 | const statusMap = { | 132 | const statusMap = { |
120 | published: 'success', | 133 | published: 'success', |
121 | draft: 'info', | 134 | draft: 'info', |
122 | deleted: 'danger' | 135 | deleted: 'danger' |
123 | } | 136 | } |
124 | return statusMap[status] | 137 | return statusMap[prod_status] |
125 | } | 138 | } |
126 | }, | 139 | }, |
127 | data() { | 140 | data() { |
128 | return { | 141 | return { |
129 | list: null, | 142 | list: null, |
130 | total: 0, | 143 | total: 0, |
131 | listLoading: true, | 144 | listLoading: true, |
132 | listQuery: { | 145 | listQuery: { |
133 | page: 1, | 146 | page: 1, |
134 | limit: 20 | 147 | limit: 20 |
135 | } | 148 | } |
136 | } | 149 | } |
137 | }, | 150 | }, |
138 | created() { | 151 | created() { |
139 | this.getList() | 152 | this.getList() |
140 | }, | 153 | }, |
141 | methods: { | 154 | methods: { |
142 | getList() { | 155 | getList() { |
143 | this.listLoading = true | 156 | this.listLoading = true |