Browse Source

add rich-editor

张延森 5 years ago
parent
commit
78277d77c6

+ 0
- 1
public/index.html View File

@@ -6,7 +6,6 @@
6 6
     <meta name="viewport" content="width=device-width,initial-scale=1.0">
7 7
     <link rel="icon" href="<%= BASE_URL %>favicon.ico">
8 8
     <link rel="stylesheet" href="//at.alicdn.com/t/font_1070150_8lyiyriedbr.css">
9
-    <script src="./static/abc.js"></script>
10 9
     <title>后台管理系统</title>
11 10
   </head>
12 11
   <body>

+ 84
- 0
src/components/EditableTag.vue View File

@@ -0,0 +1,84 @@
1
+<template>
2
+  <div>
3
+    <el-tag
4
+      :key="item[label]"
5
+      v-for="item in value"
6
+      closable
7
+      :disable-transitions="false"
8
+      @close="() => handleClose(item)">
9
+      {{item[label]}}
10
+    </el-tag>
11
+    <el-input
12
+      class="input-new-tag"
13
+      v-if="inputVisible"
14
+      v-model="inputValue"
15
+      ref="saveTagInput"
16
+      size="small"
17
+      @keyup.enter.native="handleInputConfirm"
18
+      @blur="handleInputConfirm"
19
+    >
20
+    </el-input>
21
+    <el-button v-else class="button-new-tag" size="small" @click="showInput">+ 新建</el-button>
22
+  </div>
23
+</template>
24
+
25
+<script>
26
+  export default {
27
+    name: 'EditableTag',
28
+    props: [
29
+      'value',
30
+      'label',
31
+    ],
32
+    data() {
33
+      return {
34
+        inputVisible: false,
35
+        inputValue: ''
36
+      };
37
+    },
38
+    methods: {
39
+      handleClose(item) {
40
+        this.$confirm(`确认删除 ${item[this.label]}?`, '提示', {
41
+          confirmButtonText: '确定',
42
+          cancelButtonText: '取消',
43
+          type: 'warning'
44
+        }).then(() => {
45
+          this.$emit('delete', item)
46
+        }).catch(() => {})
47
+      },
48
+
49
+      showInput() {
50
+        this.inputVisible = true;
51
+        this.$nextTick(() => {
52
+          this.$refs.saveTagInput.$refs.input.focus()
53
+        })
54
+      },
55
+
56
+      handleInputConfirm() {
57
+        let inputValue = this.inputValue
58
+        if (inputValue) {
59
+          this.$emit('insert', inputValue)
60
+        }
61
+        this.inputVisible = false
62
+        this.inputValue = ''
63
+      }
64
+    }
65
+  }
66
+</script>
67
+
68
+<style>
69
+  .el-tag + .el-tag {
70
+    margin-left: 10px;
71
+  }
72
+  .button-new-tag {
73
+    margin-left: 10px;
74
+    height: 32px;
75
+    line-height: 30px;
76
+    padding-top: 0;
77
+    padding-bottom: 0;
78
+  }
79
+  .input-new-tag {
80
+    width: 90px;
81
+    margin-left: 10px;
82
+    vertical-align: bottom;
83
+  }
84
+</style>

+ 77
- 0
src/components/RichEditor.vue View File

@@ -0,0 +1,77 @@
1
+<template>
2
+  <div ref="editor"></div>
3
+</template>
4
+
5
+<script>
6
+import E from 'wangeditor'
7
+import uploadImage from '../utils/uploadImage'
8
+
9
+export default {
10
+  name: 'RichEditor',
11
+  props: [
12
+    'value',
13
+    'setting'
14
+  ],
15
+  data () {
16
+    return {
17
+      editor: undefined,
18
+      html: '',
19
+    }
20
+  },
21
+  watch: {
22
+    value (newVal) {
23
+      const newTxt = this.getHtmlTxt(newVal)
24
+      const oriTxt = this.getHtmlTxt(this.html)
25
+
26
+      if (newTxt != oriTxt) {
27
+        this.updateContent(newVal)
28
+        this.initedContent = true
29
+      }
30
+    }
31
+  },
32
+  mounted () {
33
+    this.$nextTick(() => this.initEditor())
34
+  },
35
+  methods: {
36
+    initEditor() {
37
+      if (!this.$refs.editor) return
38
+
39
+      const editor = new E(this.$refs.editor)
40
+      this.editor = editor
41
+
42
+      if (this.setting) {
43
+        editor.customConfig = this.setting
44
+      }
45
+
46
+      // 重新定义图片上传
47
+      editor.customConfig.customUploadImg = this.uploadImg
48
+
49
+      editor.customConfig.onblur = (html) => {
50
+        this.html = html
51
+        this.$emit('input', html)
52
+      }
53
+
54
+      editor.create()
55
+
56
+      if (this.html) {
57
+        editor.txt.html(html)
58
+      }
59
+    },
60
+    uploadImg (files, insert) {
61
+      if (files.length > 0) {
62
+        uploadImage(files[0]).then(insert)
63
+      }
64
+    },
65
+    updateContent (html) {
66
+      this.html = html
67
+      if (this.editor) {
68
+        this.editor.txt.html(html)
69
+      }
70
+    },
71
+    getHtmlTxt(html) {
72
+      return (html || '').replace(/<\/?.+?\/?>/g, '')
73
+    }
74
+  }
75
+}
76
+</script>
77
+

+ 3
- 0
src/main.js View File

@@ -4,6 +4,8 @@ import ECharts from 'vue-echarts'
4 4
 import XMIcon from '@/components/XMIcon.vue'
5 5
 import XMRightLay from '@/components/XMRightLay.vue'
6 6
 import XMSearchForm from '@/components/XMSearchForm.vue'
7
+import RichEditor from '@/components/RichEditor.vue'
8
+
7 9
 import App from './App.vue'
8 10
 import router from './router'
9 11
 import store from './store'
@@ -24,6 +26,7 @@ Vue.component('v-chart', ECharts)
24 26
 Vue.component('xm-icon', XMIcon)
25 27
 Vue.component('xm-rtl', XMRightLay)
26 28
 Vue.component('xm-search', XMSearchForm)
29
+Vue.component('rich-editor', RichEditor)
27 30
 Vue.use(VueAMap)
28 31
 
29 32
 VueAMap.initAMapApiLoader({

+ 17
- 0
src/utils/uploadImage.js View File

@@ -0,0 +1,17 @@
1
+import request from './request';
2
+import apis from '../config/api';
3
+
4
+export default (file) => {
5
+  return new Promise((resolve, reject) => {
6
+    const fm = new FormData()
7
+    fm.append('file', file)
8
+    request({
9
+      ...apis.file.upload,
10
+      data: fm,
11
+    }).then((data) => {
12
+      resolve(data)
13
+    }).catch((err) => {
14
+      reject(err.message || err)
15
+    })
16
+  })
17
+}

+ 26
- 50
src/views/building/edit.vue View File

@@ -1,7 +1,7 @@
1 1
 <template>
2 2
   <el-tabs v-model="activeName">
3 3
     <el-tab-pane label="基础信息" name="detail">
4
-      <el-form ref="form" :model="building" label-width="160px">
4
+      <el-form ref="form" :model="building" label-width="160px" class="building-form">
5 5
         <el-form-item label="楼盘编号">
6 6
           <el-input v-model="building.code"></el-input>
7 7
         </el-form-item>
@@ -101,7 +101,7 @@
101 101
           </el-radio-group>
102 102
         </el-form-item>
103 103
         <el-form-item label="项目备注">
104
-          <div id="websiteEditorElem" style="height: 400px"></div>
104
+          <rich-editor v-model="building.remark" style="height: 400px" />
105 105
         </el-form-item>
106 106
         <el-form-item label="楼盘区域">
107 107
           <el-input v-model="building.buildingArea"></el-input>
@@ -238,14 +238,10 @@
238 238
 import { createNamespacedHelpers } from 'vuex'
239 239
 import apis from '../../config/api'
240 240
 import { mapState } from 'vuex'
241
-import E from 'wangeditor'
242 241
 
243 242
 const { mapState: mapBuildingState, mapActions: mapBuildingActions, mapMutations: mapBuildingMutations } = createNamespacedHelpers('building')
244
-
245 243
 const { mapActions: mapApartmentActions } = createNamespacedHelpers('apartment')
246 244
 
247
-const { mapActions: mapImgActions } = createNamespacedHelpers('img')
248
-
249 245
 export default {
250 246
   data () {
251 247
     var _self = this
@@ -334,9 +330,6 @@ export default {
334 330
       'editApartment',
335 331
       'deleteApartment'
336 332
     ]),
337
-    ...mapImgActions([
338
-      'uploadImg'
339
-    ]),
340 333
     getSaleTypeName (id) {
341 334
       return (this.saleType.filter(x => x.id == id) [0] || {}).name
342 335
     },
@@ -503,54 +496,37 @@ export default {
503 496
           this.getAparmentList()
504 497
         })
505 498
       })
499
+    },
500
+    initData () {
501
+      if ((this.$route.query.id || '') !== '') {
502
+        this.getAparmentList()
503
+        this.getDetail({id: this.$route.query.id}).then(data => {
504
+          this.buildingProperty = data.propertyType.split(',')
505
+          this.imgList = data.buildingImg.map(x => {
506
+            return {
507
+              name: x.imgId,
508
+              url: x.url
509
+            }
510
+          })
511
+          this.tags = data.buildingTag.map(x => x.tagName)
512
+        })
513
+      }
506 514
     }
507 515
   },
508 516
   mounted () {
509
-    const _that = this
510
-    const phoneEditor = new E('#websiteEditorElem')
511
-    phoneEditor.customConfig.onchange = function (html) {
512
-      _that.building = {..._that.building, remark: html}
513
-    }
514
-    phoneEditor.customConfig.customUploadImg = function (files, insert) {
515
-      _that.uploadImg(files[0]).then(data => {
516
-        insert(data[0])
517
-      })
518
-    }
519
-    phoneEditor.customConfig.menus = [
520
-      'head',  // 标题
521
-      'bold',  // 粗体
522
-      'fontSize',  // 字号
523
-      'fontName',  // 字体
524
-      'italic',  // 斜体
525
-      'underline',  // 下划线
526
-      'strikeThrough',  // 删除线
527
-      'foreColor',  // 文字颜色
528
-      'backColor',  // 背景颜色
529
-      'justify',  // 对齐方式
530
-      'image',  // 插入图片
531
-    ]
532
-    phoneEditor.create()
533
-    if ((this.$route.query.id || '') !== '') {
534
-      this.getAparmentList()
535
-      window.console.log(this.getDetail)
536
-      this.getDetail({id: this.$route.query.id}).then(data => {
537
-        this.buildingProperty = data.propertyType.split(',')
538
-        phoneEditor.txt.html(data.remark)
539
-        this.imgList = data.buildingImg.map(x => {
540
-          return {
541
-            name: x.imgId,
542
-            url: x.url
543
-          }
544
-        })
545
-        this.tags = data.buildingTag.map(x => x.tagName)
546
-      })
547
-    } else {
548
-      phoneEditor.txt.html('')
549
-    }
517
+    this.initData()
550 518
   }
551 519
 }
552 520
 </script>
553 521
 
522
+<style lang="scss" scoped>
523
+.building-form {
524
+  width: 60%;
525
+  min-width: 500px;
526
+}
527
+</style>
528
+
529
+
554 530
 <style lang="scss">
555 531
 .header{
556 532
   width: 50px;