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 |