Commit a86b16bba66bd2283ef0acc24ff86ac1ef8adb67

Authored by Adam
1 parent 0bd81688e7
Exists in master

auto commit the code by alias command

... ... @@ -2,5 +2,5 @@
2 2 ENV = 'production'
3 3  
4 4 # base api
5   -VUE_APP_BASE_API = '/prod-api'
6   -
  5 +#VUE_APP_BASE_API = '/prod-api'
  6 +VUE_APP_BASE_API = 'https://api.glass.xiuyetang.com/'
... ...
1 1 import Mock from 'mockjs'
2   -import { param2Obj } from '../src/utils'
  2 +import {
  3 + param2Obj
  4 +} from '../src/utils'
3 5  
4 6 import user from './user'
5 7 import role from './role'
  8 +import prod from './prod'
6 9 import article from './article'
7 10 import search from './remote-search'
8   -
  11 +//因为没有Mock上,所以会请求不到数据。报404
9 12 const mocks = [
10 13 ...user,
11 14 ...role,
12 15 ...article,
  16 + ...prod,
13 17 ...search
14 18 ]
15 19  
... ... @@ -20,7 +24,7 @@ export function mockXHR() {
20 24 // mock patch
21 25 // https://github.com/nuysoft/Mock/issues/300
22 26 Mock.XHR.prototype.proxy_send = Mock.XHR.prototype.send
23   - Mock.XHR.prototype.send = function() {
  27 + Mock.XHR.prototype.send = function () {
24 28 if (this.custom.xhr) {
25 29 this.custom.xhr.withCredentials = this.withCredentials || false
26 30  
... ... @@ -32,10 +36,14 @@ export function mockXHR() {
32 36 }
33 37  
34 38 function XHR2ExpressReqWrap(respond) {
35   - return function(options) {
  39 + return function (options) {
36 40 let result = null
37 41 if (respond instanceof Function) {
38   - const { body, type, url } = options
  42 + const {
  43 + body,
  44 + type,
  45 + url
  46 + } = options
39 47 // https://expressjs.com/en/4x/api.html#req
40 48 result = respond({
41 49 method: type,
... ...
... ... @@ -10,21 +10,29 @@ const image_uri = 'https://wpimg.wallstcn.com/360e4842-4db5-42d0-b078-f9a84a8255
10 10  
11 11 for (let i = 0; i < count; i++) {
12 12 List.push(Mock.mock({
13   - pid: '@increment',
14   - pname: '@title(5,10)',
15   - timestamp: +Mock.Random.date('T'),
  13 + pid: '@increment', //产品id
  14 + pname: '01-8701志平防蓝光-防辐射电脑网课眼镜,TR90弹性漆,近视镜,青春潮流', //产品名移交
  15 + timestamp: +Mock.Random.date('T'), //产品时间
16 16 shoper: '@first', //所属工厂
17 17 salescount: '@first', //购买次数
18   - importance: '@integer(1, 3)', //排序权重
19   - prod_info_weight: '@integer(1, 3)', //重量
20   - prod_info_leg_long: '@integer(1, 3)', //腿长
21   - prod_info_glass_width: '@integer(1, 3)', //镜宽
22   - prod_info_glass_height: '@integer(1, 3)', //镜高
23   - prod_info_frame_width: '@integer(1, 3)', //框宽
24   - prod_info_frame_height: '@integer(1, 3)', //框高
25   - prod_info_norse_width: '@integer(1, 3)', //鼻宽
  18 + importance: '@integer(1, 3)', //排序-权重
  19 + prod_info_weight: '@integer(1, 3)', //参数--->重量
  20 + prod_info_leg_long: '@integer(1, 3)', //参数--->腿长
  21 + prod_info_glass_width: '@integer(1, 3)', //参数--->镜宽
  22 + prod_info_glass_height: '@integer(1, 3)', //参数--->镜高
  23 + prod_info_frame_width: '@integer(1, 3)', //参数--->框宽
  24 + prod_info_frame_height: '@integer(1, 3)', //参数--->框高
  25 + prod_info_norse_width: '@integer(1, 3)', //参数--->鼻宽
26 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  
... ... @@ -35,23 +43,22 @@ export default [{
35 43 const {
36 44 importance,
37 45 type,
38   - title,
  46 + pname,
39 47 page = 1,
40 48 limit = 20,
41   - sort
  49 + // sort
42 50 } = config.query
43 51  
44 52 let mockList = List.filter(item => {
45 53 if (importance && item.importance !== +importance) return false
46 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 56 return true
49 57 })
50 58  
51   - if (sort === '-id') {
52   - mockList = mockList.reverse()
53   - }
54   -
  59 + // if (sort === '-pid') {
  60 + // mockList = mockList.reverse()
  61 + // }
55 62 const pageList = mockList.filter((item, index) => index < limit * page && index >= limit * (page - 1))
56 63  
57 64 return {
... ... @@ -63,16 +70,15 @@ export default [{
63 70 }
64 71 }
65 72 },
66   -
67 73 {
68 74 url: '/yp/prod/detail',
69 75 type: 'get',
70 76 response: config => {
71 77 const {
72   - id
  78 + pid
73 79 } = config.query
74 80 for (const prod of List) {
75   - if (prod.id === +id) {
  81 + if (prod.pid === +pid) {
76 82 return {
77 83 code: 20000,
78 84 data: prod
... ... @@ -82,34 +88,34 @@ export default [{
82 88 }
83 89 },
84 90  
85   - {
86   - url: '/yp/prod/pv',
87   - type: 'get',
88   - response: _ => {
89   - return {
90   - code: 20000,
91   - data: {
92   - pvData: [{
93   - key: 'PC',
94   - pv: 1024
95   - },
96   - {
97   - key: 'mobile',
98   - pv: 1024
99   - },
100   - {
101   - key: 'ios',
102   - pv: 1024
103   - },
104   - {
105   - key: 'android',
106   - pv: 1024
107   - }
108   - ]
109   - }
110   - }
111   - }
112   - },
  91 + // {
  92 + // url: '/yp/prod/pv',
  93 + // type: 'get',
  94 + // response: _ => {
  95 + // return {
  96 + // code: 20000,
  97 + // data: {
  98 + // pvData: [{
  99 + // key: 'PC',
  100 + // pv: 1024
  101 + // },
  102 + // {
  103 + // key: 'mobile',
  104 + // pv: 1024
  105 + // },
  106 + // {
  107 + // key: 'ios',
  108 + // pv: 1024
  109 + // },
  110 + // {
  111 + // key: 'android',
  112 + // pv: 1024
  113 + // }
  114 + // ]
  115 + // }
  116 + // }
  117 + // }
  118 + // },
113 119  
114 120 {
115 121 url: '/yp/prod/create',
... ...
... ... @@ -12,16 +12,16 @@ export function fetchList(query) {
12 12 return request({
13 13 url: '/yp/prod/list',
14 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 20 return request({
21 21 url: '/yp/prod/detail',
22 22 method: 'get',
23 23 params: {
24   - id
  24 + pid
25 25 }
26 26 })
27 27 }
... ...
src/components/Pagination/index.vue
1 1 <template>
2   - <div :class="{'hidden':hidden}" class="pagination-container">
  2 + <div
  3 + :class="{'hidden':hidden}"
  4 + class="pagination-container"
  5 + >
3 6 <el-pagination
4 7 :background="background"
5 8 :current-page.sync="currentPage"
... ...
... ... @@ -79,7 +79,10 @@ export default {
79 79 prodlist: '产品列表'
80 80 },
81 81 orders: '订单',
82   - sites: '站点',
  82 + sites: {
  83 + sites: '站点',
  84 + siteList: '站点列表'
  85 + },
83 86 metas: {
84 87 metas: '元',
85 88 list: '树'
... ...
src/router/modules/prod.js
... ... @@ -16,11 +16,31 @@ const prodRouter = {
16 16 children: [{
17 17 path: 'list',
18 18 component: () => import('@/views/prod/list'),
19   - name: 'prodList',
  19 + name: 'ProdList',
20 20 meta: {
21 21 title: 'prods.prodlist',
22 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  
... ...
src/router/modules/sites.js
... ... @@ -7,7 +7,7 @@ const sitesRouter = {
7 7 alwaysShow: true, // will always show the root menu
8 8 name: 'Site',
9 9 meta: {
10   - title: 'sites',
  10 + title: 'sites.sites',
11 11 icon: 'people',
12 12 roles: ['admin', 'assistant', 'runner'] // you can set roles in root nav
13 13 },
... ... @@ -16,7 +16,7 @@ const sitesRouter = {
16 16 component: () => import('@/views/site/list'),
17 17 name: 'SiteList',
18 18 meta: {
19   - title: '站点列表',
  19 + title: 'sites.siteList',
20 20 roles: ['admin', 'runner']
21 21  
22 22 }
... ...
src/store/modules/settings.js
1 1 import variables from '@/styles/element-variables.scss'
2 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 12 const state = {
7 13 theme: variables.theme,
... ... @@ -13,7 +19,10 @@ const state = {
13 19 }
14 20  
15 21 const mutations = {
16   - CHANGE_SETTING: (state, { key, value }) => {
  22 + CHANGE_SETTING: (state, {
  23 + key,
  24 + value
  25 + }) => {
17 26 if (state.hasOwnProperty(key)) {
18 27 state[key] = value
19 28 }
... ... @@ -21,7 +30,9 @@ const mutations = {
21 30 }
22 31  
23 32 const actions = {
24   - changeSetting({ commit }, data) {
  33 + changeSetting({
  34 + commit
  35 + }, data) {
25 36 commit('CHANGE_SETTING', data)
26 37 }
27 38 }
... ... @@ -32,4 +43,3 @@ export default {
32 43 mutations,
33 44 actions
34 45 }
35   -
... ...
src/utils/request.js
... ... @@ -40,21 +40,13 @@ service.interceptors.request.use(
40 40 'Content-Type': 'application/x-www-form-urlencoded'
41 41 }
42 42 }
43   - // let options = {
44   - // lock: true,
45   - // fullscreen: false,
46   - // text: '数据加载中……',
47   - // // background: '#FFCC00',
48   - // spinner: 'el-icon-loading'
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)
  43 + // Notification({
  44 + // type: 'success',
  45 + // message: baseUrl + config.url,
  46 + // title: 'request axios ',
  47 + // showClose: true,
  48 + // duration: 3000
  49 + // })
58 50 // loadingInstance = Loading.service(options);
59 51 config.method === 'post'
60 52 ? config.data = qs.stringify({
... ... @@ -75,7 +67,6 @@ service.interceptors.request.use(
75 67 // do something before request is sent
76 68 },
77 69 error => {
78   - // do something with request error
79 70 Message({
80 71 message: error || 'Error',
81 72 type: 'error',
... ... @@ -100,7 +91,7 @@ service.interceptors.response.use(
100 91 */
101 92 response => {
102 93 const options = {
103   - type: 'error',
  94 + type: response.status == 200 ? 'success' : 'error',
104 95 message: response.status,
105 96 title: 'response status value ',
106 97 showClose: true,
... ...
src/views/example/list.vue
1 1 <template>
2 2 <div class="app-container">
3   - <el-table v-loading="listLoading" :data="list" border fit highlight-current-row style="width: 100%">
4   - <el-table-column align="center" label="ID" width="80">
  3 + <el-table
  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 16 <template slot-scope="scope">
6 17 <span>{{ scope.row.id }}</span>
7 18 </template>
8 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 26 <template slot-scope="scope">
12 27 <span>{{ scope.row.timestamp | parseTime('{y}-{m}-{d} {h}:{i}') }}</span>
13 28 </template>
14 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 36 <template slot-scope="scope">
18 37 <span>{{ scope.row.author }}</span>
19 38 </template>
20 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 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 52 </template>
26 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 60 <template slot-scope="{row}">
30 61 <el-tag :type="row.status | statusFilter">
31 62 {{ row.status }}
... ... @@ -33,18 +64,32 @@
33 64 </template>
34 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 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 76 <span>{{ row.title }}</span>
40 77 </router-link>
41 78 </template>
42 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 86 <template slot-scope="scope">
46 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 93 Edit
49 94 </el-button>
50 95 </router-link>
... ... @@ -52,7 +97,13 @@
52 97 </el-table-column>
53 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 107 </div>
57 108 </template>
58 109  
... ...
src/views/prod/components/Dropdown/Comment.vue
... ... @@ -0,0 +1,41 @@
  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>
... ...
src/views/prod/components/Dropdown/Platform.vue
... ... @@ -0,0 +1,46 @@
  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>
... ...
src/views/prod/components/Dropdown/SourceUrl.vue
... ... @@ -0,0 +1,38 @@
  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>
... ...
src/views/prod/components/Dropdown/index.js
... ... @@ -0,0 +1,3 @@
  1 +export { default as CommentDropdown } from './Comment'
  2 +export { default as PlatformDropdown } from './Platform'
  3 +export { default as SourceUrlDropdown } from './SourceUrl'
... ...
src/views/prod/components/ProdDetail.vue
... ... @@ -0,0 +1,388 @@
  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>
... ...
src/views/prod/components/Warning.vue
... ... @@ -0,0 +1,10 @@
  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 +
... ...
src/views/prod/create.vue
... ... @@ -0,0 +1,16 @@
  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 +
... ...
src/views/prod/edit.vue
... ... @@ -0,0 +1,13 @@
  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 +
... ...
src/views/prod/list.vue
1 1 <template>
2 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 17 <el-table
4 18 v-loading="listLoading"
5 19 :data="list"
... ... @@ -10,39 +24,45 @@
10 24 >
11 25 <el-table-column
12 26 align="center"
13   - label="ID"
14   - width="80"
  27 + label="pid"
15 28 >
16 29 <template slot-scope="scope">
17   - <span>{{ scope.row.id }}</span>
  30 + <span>{{ scope.row.pid }}</span>
18 31 </template>
19 32 </el-table-column>
20   -
21 33 <el-table-column
22   - width="180px"
23 34 align="center"
24   - label="Date"
  35 + label="pname"
25 36 >
26 37 <template slot-scope="scope">
27   - <span>{{ scope.row.timestamp | parseTime('{y}-{m}-{d} {h}:{i}') }}</span>
  38 + <span>{{ scope.row.pname }}</span>
28 39 </template>
29 40 </el-table-column>
30   -
31 41 <el-table-column
32   - width="120px"
33 42 align="center"
34   - label="Author"
  43 + label="参数信息"
35 44 >
36 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 52 </template>
39 53 </el-table-column>
40 54  
41 55 <el-table-column
42   - width="100px"
43   - label="Importance"
  56 + align="center"
  57 + label="Date"
44 58 >
45 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 66 <svg-icon
47 67 v-for="n in +scope.row.importance"
48 68 :key="n"
... ... @@ -54,43 +74,36 @@
54 74  
55 75 <el-table-column
56 76 class-name="status-col"
57   - label="Status"
58   - width="110"
  77 + label="prod_status"
59 78 >
60 79 <template slot-scope="{row}">
61   - <el-tag :type="row.status | statusFilter">
62   - {{ row.status }}
  80 + <el-tag :type="row.prod_status | statusFilter">
  81 + {{ row.prod_status }}
63 82 </el-tag>
64 83 </template>
65 84 </el-table-column>
66 85  
67 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 87 align="center"
83 88 label="Actions"
84   - width="120"
85 89 >
86   - <template slot-scope="scope">
87   - <router-link :to="'/example/edit/'+scope.row.id">
  90 + <template slot-scope="{row}">
  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 101 <el-button
89 102 type="primary"
90 103 size="small"
91 104 icon="el-icon-edit"
92 105 >
93   - Edit
  106 + Edit2
94 107 </el-button>
95 108 </router-link>
96 109 </template>
... ... @@ -108,20 +121,20 @@
108 121 </template>
109 122  
110 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 126 import Pagination from '@/components/Pagination' // Secondary package based on el-pagination
113   -
114 127 export default {
115   - name: 'ArticleList',
  128 + name: 'ProdList',
116 129 components: { Pagination },
117 130 filters: {
118   - statusFilter(status) {
  131 + statusFilter(prod_status) {
119 132 const statusMap = {
120 133 published: 'success',
121 134 draft: 'info',
122 135 deleted: 'danger'
123 136 }
124   - return statusMap[status]
  137 + return statusMap[prod_status]
125 138 }
126 139 },
127 140 data() {
... ... @@ -141,6 +154,7 @@ export default {
141 154 methods: {
142 155 getList() {
143 156 this.listLoading = true
  157 + console.log('getList', 'dddddd')
144 158 fetchList(this.listQuery).then(response => {
145 159 this.list = response.data.items
146 160 this.total = response.data.total
... ...