Browse Source

add ricttext

wxb 5 năm trước cách đây
mục cha
commit
934c59dd05

+ 1 - 0
package.json

@@ -44,6 +44,7 @@
   },
   "dependencies": {
     "@riophae/vue-treeselect": "0.4.0",
+    "@tinymce/tinymce-vue": "^3.2.2",
     "awe-dnd": "^0.3.4",
     "axios": "0.19.2",
     "clipboard": "2.0.6",

+ 1 - 0
src/components/FileChoose/index.vue

@@ -3,6 +3,7 @@
     <el-dialog
       :visible.sync="dialog"
       width="30%"
+      append-to-body
       :before-close="handleClose"
     >
       <div slot="title" class="file-title">

+ 13 - 67
src/components/Tinymce/components/EditorImage.vue

@@ -1,39 +1,21 @@
 <template>
   <div class="upload-container">
-    <el-button :style="{background:color,borderColor:color}" icon="el-icon-upload" size="mini" type="primary" @click=" dialogVisible=true">
+    <el-button :style="{background:color,borderColor:color}" icon="el-icon-upload" size="mini" type="primary" @click="handleFile">
       upload
     </el-button>
-    <el-dialog :visible.sync="dialogVisible">
-      <el-upload
-        :multiple="true"
-        :file-list="fileList"
-        :show-file-list="true"
-        :on-remove="handleRemove"
-        :on-success="handleSuccess"
-        :before-upload="beforeUpload"
-        class="editor-slide-upload"
-        action="https://httpbin.org/post"
-        list-type="picture-card"
-      >
-        <el-button size="small" type="primary">
-          Click upload
-        </el-button>
-      </el-upload>
-      <el-button @click="dialogVisible = false">
-        Cancel
-      </el-button>
-      <el-button type="primary" @click="handleSubmit">
-        Confirm
-      </el-button>
-    </el-dialog>
+    <file-choose :dialog-form-visible="dialogVisible" @close="handleFileClose" @confirm="handleFileConfirm" />
   </div>
 </template>
 
 <script>
 // import { getToken } from 'api/qiniu'
 
+import FileChoose from '../../FileChoose/index'
 export default {
   name: 'EditorSlideUpload',
+  components: {
+    FileChoose
+  },
   props: {
     color: {
       type: String,
@@ -51,51 +33,15 @@ export default {
     checkAllSuccess() {
       return Object.keys(this.listObj).every(item => this.listObj[item].hasSuccess)
     },
-    handleSubmit() {
-      const arr = Object.keys(this.listObj).map(v => this.listObj[v])
-      if (!this.checkAllSuccess()) {
-        this.$message('Please wait for all images to be uploaded successfully. If there is a network problem, please refresh the page and upload again!')
-        return
-      }
-      this.$emit('successCBK', arr)
-      this.listObj = {}
-      this.fileList = []
-      this.dialogVisible = false
-    },
-    handleSuccess(response, file) {
-      const uid = file.uid
-      const objKeyArr = Object.keys(this.listObj)
-      for (let i = 0, len = objKeyArr.length; i < len; i++) {
-        if (this.listObj[objKeyArr[i]].uid === uid) {
-          this.listObj[objKeyArr[i]].url = response.files.file
-          this.listObj[objKeyArr[i]].hasSuccess = true
-          return
-        }
-      }
+    handleFile() {
+      this.dialogVisible = !this.dialogVisible
     },
-    handleRemove(file) {
-      const uid = file.uid
-      const objKeyArr = Object.keys(this.listObj)
-      for (let i = 0, len = objKeyArr.length; i < len; i++) {
-        if (this.listObj[objKeyArr[i]].uid === uid) {
-          delete this.listObj[objKeyArr[i]]
-          return
-        }
-      }
+    handleFileClose() {
+      this.dialogVisible = false
     },
-    beforeUpload(file) {
-      const _self = this
-      const _URL = window.URL || window.webkitURL
-      const fileName = file.uid
-      this.listObj[fileName] = {}
-      return new Promise((resolve, reject) => {
-        const img = new Image()
-        img.src = _URL.createObjectURL(file)
-        img.onload = function() {
-          _self.listObj[fileName] = { hasSuccess: false, uid: file.uid, width: this.width, height: this.height }
-        }
-        resolve(true)
-      })
+    handleFileConfirm(e) {
+      this.dialogVisible = false
+      console.log(e)
     }
   }
 }

+ 14 - 6
src/components/Tinymce/index.vue

@@ -116,20 +116,21 @@ export default {
       const _this = this
       window.tinymce.init({
         selector: `#${this.tinymceId}`,
-        language: this.languageTypeList['en'],
+        language: this.languageTypeList['zh'],
         height: this.height,
         body_class: 'panel-body ',
         object_resizing: false,
         toolbar: this.toolbar.length > 0 ? this.toolbar : toolbar,
         menubar: this.menubar,
         plugins: plugins,
+        branding: false,
         end_container_on_empty_block: true,
         powerpaste_word_import: 'clean',
         code_dialog_height: 450,
         code_dialog_width: 1000,
         advlist_bullet_styles: 'square',
         advlist_number_styles: 'default',
-        imagetools_cors_hosts: ['www.tinymce.com', 'codepen.io'],
+        // imagetools_cors_hosts: ['www.tinymce.com', 'codepen.io'],
         default_link_target: '_blank',
         link_title: false,
         nonbreaking_force_tab: true, // inserting nonbreaking space &nbsp; need Nonbreaking Space Plugin
@@ -209,10 +210,17 @@ export default {
 }
 </script>
 
-<style scoped>
-.tinymce-container {
+<style lang="scss" scoped>
+
+.tinymce-container /deep/{
   position: relative;
   line-height: normal;
+  width: 100%;
+  padding: 0 20px 0 0;
+  box-sizing: border-box;
+  .mce-btn{
+	float: left!important;
+  }
 }
 .tinymce-container>>>.mce-fullscreen {
   z-index: 10000;
@@ -221,11 +229,11 @@ export default {
   visibility: hidden;
   z-index: -1;
 }
-.editor-custom-btn-container {
+.editor-custom-btn-container{
   position: absolute;
   right: 4px;
   top: 4px;
-  /*z-index: 2005;*/
+  right: 30px;
 }
 .fullscreen .editor-custom-btn-container {
   z-index: 10000;

+ 1 - 1
src/components/Tinymce/plugins.js

@@ -2,6 +2,6 @@
 // Detail plugins list see https://www.tinymce.com/docs/plugins/
 // Custom builds see https://www.tinymce.com/download/custom-builds/
 
-const plugins = ['advlist anchor autolink autosave code codesample colorpicker colorpicker contextmenu directionality emoticons fullscreen hr image imagetools insertdatetime link lists media nonbreaking noneditable pagebreak paste preview print save searchreplace spellchecker tabfocus table template textcolor textpattern visualblocks visualchars wordcount']
+const plugins = ['advlist anchor autolink autosave code codesample colorpicker colorpicker contextmenu directionality emoticons fullscreen hr insertdatetime link lists media nonbreaking noneditable pagebreak paste preview print save searchreplace spellchecker tabfocus table template textcolor textpattern visualblocks visualchars wordcount']
 
 export default plugins

+ 1 - 1
src/components/Tinymce/toolbar.js

@@ -1,6 +1,6 @@
 // Here is a list of the toolbar
 // Detail list see https://www.tinymce.com/docs/advanced/editor-control-identifiers/#toolbarcontrols
 
-const toolbar = ['searchreplace bold italic underline strikethrough alignleft aligncenter alignright outdent indent  blockquote undo redo removeformat subscript superscript code codesample', 'hr bullist numlist link image charmap preview anchor pagebreak insertdatetime media table emoticons forecolor backcolor fullscreen']
+const toolbar = ['searchreplace bold italic underline strikethrough alignleft aligncenter alignright outdent indent  blockquote undo redo removeformat subscript superscript code codesample hr bullist numlist link image charmap preview anchor pagebreak insertdatetime media table emoticons forecolor backcolor fullscreen']
 
 export default toolbar

+ 209 - 0
src/styles/admin.css

@@ -0,0 +1,209 @@
+@charset "UTF-8";
+/**
+ * 通用css样式布局处理
+ * Copyright (c) 2019 ruoyi
+ */
+/** 基础通用 **/
+.pt5 {
+  padding-top: 5px;
+}
+
+.pr5 {
+  padding-right: 5px;
+}
+
+.pb5 {
+  padding-bottom: 5px;
+}
+
+.mt5 {
+  margin-top: 5px;
+}
+
+.mr5 {
+  margin-right: 5px;
+}
+
+.mb5 {
+  margin-bottom: 5px;
+}
+
+.mb8 {
+  margin-bottom: 8px;
+}
+
+.ml5 {
+  margin-left: 5px;
+}
+
+.mt10 {
+  margin-top: 10px;
+}
+
+.mr10 {
+  margin-right: 10px;
+}
+
+.mb10 {
+  margin-bottom: 10px;
+}
+
+.ml0 {
+  margin-left: 10px;
+}
+
+.mt20 {
+  margin-top: 20px;
+}
+
+.mr20 {
+  margin-right: 20px;
+}
+
+.mb20 {
+  margin-bottom: 20px;
+}
+
+.m20 {
+  margin-left: 20px;
+}
+
+.el-dialog {
+  margin-top: 6vh !important;
+}
+
+.el-table .el-table__header-wrapper th {
+  word-break: break-word;
+  background-color: #f8f8f9;
+  color: #515a6e;
+  height: 40px;
+  font-size: 13px;
+}
+
+/** 表单布局 **/
+.form-header {
+  font-size: 15px;
+  color: #6379bb;
+  border-bottom: 1px solid #ddd;
+  margin: 8px 10px 25px 10px;
+  padding-bottom: 5px;
+}
+
+/** 表格布局 **/
+.pagination-container {
+  position: relative;
+  height: 25px;
+  margin-bottom: 10px;
+  margin-top: 15px;
+  padding: 10px 20px !important;
+}
+
+.pagination-container .el-pagination {
+  right: 0;
+  position: absolute;
+}
+
+.el-table .fixed-width .el-button--mini {
+  color: #409EFF;
+  padding-left: 0;
+  padding-right: 0;
+  width: inherit;
+}
+
+.el-tree-node__content > .el-checkbox {
+  margin-right: 8px;
+}
+
+.list-group-striped > .list-group-item {
+  border-left: 0;
+  border-right: 0;
+  border-radius: 0;
+  padding-left: 0;
+  padding-right: 0;
+}
+
+.list-group {
+  padding-left: 0px;
+  list-style: none;
+}
+
+.list-group-item {
+  border-bottom: 1px solid #e7eaec;
+  border-top: 1px solid #e7eaec;
+  margin-bottom: -1px;
+  padding: 11px 0px;
+  font-size: 13px;
+}
+
+.pull-right {
+  float: right !important;
+}
+
+.el-card__header {
+  padding: 14px 15px 7px;
+  min-height: 40px;
+}
+
+.el-card__body {
+  padding: 15px 20px 20px 20px;
+}
+
+.card-box {
+  padding-right: 15px;
+  padding-left: 15px;
+  margin-bottom: 10px;
+}
+
+/* text color */
+.text-navy {
+  color: #1ab394;
+}
+
+.text-primary {
+  color: inherit;
+}
+
+.text-success {
+  color: #1c84c6;
+}
+
+.text-info {
+  color: #23c6c8;
+}
+
+.text-warning {
+  color: #f8ac59;
+}
+
+.text-danger {
+  color: #ed5565;
+}
+
+.text-muted {
+  color: #888888;
+}
+
+/* image */
+.img-circle {
+  border-radius: 50%;
+}
+
+.img-lg {
+  width: 120px;
+  height: 120px;
+}
+
+.avatar-upload-preview {
+  position: absolute;
+  top: 50%;
+  transform: translate(50%, -50%);
+  width: 180px;
+  height: 180px;
+  border-radius: 50%;
+  box-shadow: 0 0 4px #ccc;
+  overflow: hidden;
+}
+
+.el-tabs__item {
+  font-size: 13px;
+}

+ 1 - 0
src/styles/admin.min.css

@@ -0,0 +1 @@
+.pt5{padding-top:5px}.pr5{padding-right:5px}.pb5{padding-bottom:5px}.mt5{margin-top:5px}.mr5{margin-right:5px}.mb5{margin-bottom:5px}.mb8{margin-bottom:8px}.ml5{margin-left:5px}.mt10{margin-top:10px}.mr10{margin-right:10px}.mb10{margin-bottom:10px}.ml0{margin-left:10px}.mt20{margin-top:20px}.mr20{margin-right:20px}.mb20{margin-bottom:20px}.m20{margin-left:20px}.el-dialog{margin-top:6vh !important}.el-table .el-table__header-wrapper th{word-break:break-word;background-color:#f8f8f9;color:#515a6e;height:40px;font-size:13px}.form-header{font-size:15px;color:#6379bb;border-bottom:1px solid #ddd;margin:8px 10px 25px 10px;padding-bottom:5px}.pagination-container{position:relative;height:25px;margin-bottom:10px;margin-top:15px;padding:10px 20px !important}.pagination-container .el-pagination{right:0;position:absolute}.el-table .fixed-width .el-button--mini{color:#409EFF;padding-left:0;padding-right:0;width:inherit}.el-tree-node__content>.el-checkbox{margin-right:8px}.list-group-striped>.list-group-item{border-left:0;border-right:0;border-radius:0;padding-left:0;padding-right:0}.list-group{padding-left:0px;list-style:none}.list-group-item{border-bottom:1px solid #e7eaec;border-top:1px solid #e7eaec;margin-bottom:-1px;padding:11px 0px;font-size:13px}.pull-right{float:right !important}.el-card__header{padding:14px 15px 7px;min-height:40px}.el-card__body{padding:15px 20px 20px 20px}.card-box{padding-right:15px;padding-left:15px;margin-bottom:10px}.text-navy{color:#1ab394}.text-primary{color:inherit}.text-success{color:#1c84c6}.text-info{color:#23c6c8}.text-warning{color:#f8ac59}.text-danger{color:#ed5565}.text-muted{color:#888888}.img-circle{border-radius:50%}.img-lg{width:120px;height:120px}.avatar-upload-preview{position:absolute;top:50%;transform:translate(50%, -50%);width:180px;height:180px;border-radius:50%;box-shadow:0 0 4px #ccc;overflow:hidden}.el-tabs__item{font-size:13px}

+ 3 - 1
src/styles/admin.scss

@@ -191,4 +191,6 @@
 
 .el-tabs__item{
 	font-size: 13px;
-}
+}
+
+

+ 70 - 65
src/views/syscontent/index.vue

@@ -136,76 +136,78 @@
         />
 
         <!-- 添加或修改对话框 -->
-        <el-dialog :title="title" :visible.sync="open" width="500px">
-          <el-form ref="form" :model="form" :rules="rules" label-width="80px">
-
-            <el-form-item label="分类id" prop="cateId">
-              <el-select
-                v-model="form.cateId"
-                placeholder="请选择"
-              >
-                <el-option
-                  v-for="dict in cateIdOptions"
-                  :key="dict.key"
-                  :label="dict.value"
-                  :value="dict.key"
+        <el-dialog :title="title" :visible.sync="open" width="53%">
+          <el-scrollbar style="height:600px">
+            <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+              <el-form-item label="分类id" prop="cateId">
+                <el-select
+                  v-model="form.cateId"
+                  placeholder="请选择"
+                >
+                  <el-option
+                    v-for="dict in cateIdOptions"
+                    :key="dict.key"
+                    :label="dict.value"
+                    :value="dict.key"
+                  />
+                </el-select>
+              </el-form-item>
+              <el-form-item label="名称" prop="name">
+                <el-input
+                  v-model="form.name"
+                  placeholder="名称"
+                />
+              </el-form-item>
+              <el-form-item label="状态" prop="status">
+                <el-select
+                  v-model="form.status"
+                  placeholder="请选择"
+                >
+                  <el-option
+                    v-for="dict in statusOptions"
+                    :key="dict.dictValue"
+                    :label="dict.dictLabel"
+                    :value="dict.dictValue"
+                  />
+                </el-select>
+              </el-form-item>
+              <el-form-item label="图片" prop="img">
+                <el-input
+                  v-model="form.img"
+                  placeholder="图片"
                 />
-              </el-select>
-            </el-form-item>
-            <el-form-item label="名称" prop="name">
-              <el-input
-                v-model="form.name"
-                placeholder="名称"
-              />
-            </el-form-item>
-            <el-form-item label="状态" prop="status">
-              <el-select
-                v-model="form.status"
-                placeholder="请选择"
-              >
-                <el-option
-                  v-for="dict in statusOptions"
-                  :key="dict.dictValue"
-                  :label="dict.dictLabel"
-                  :value="dict.dictValue"
+                <el-button type="primary" @click="fileShow">选择文件</el-button>
+              </el-form-item>
+              <el-form-item label="图片" prop="img">
+                <el-input
+                  v-model="form.img1"
+                  placeholder="图片"
                 />
-              </el-select>
-            </el-form-item>
-            <el-form-item label="图片" prop="img">
-              <el-input
-                v-model="form.img"
-                placeholder="图片"
-              />
-              <el-button type="primary" @click="fileShow">选择文件</el-button>
-            </el-form-item>
-            <el-form-item label="图片" prop="img">
-              <el-input
-                v-model="form.img1"
-                placeholder="图片"
-              />
-              <el-button type="primary" @click="fileShow1">选择文件</el-button>
-            </el-form-item>
-            <el-form-item label="内容" prop="content">
-              <el-input
+                <el-button type="primary" @click="fileShow1">选择文件</el-button>
+              </el-form-item>
+              <el-form-item label="内容" prop="content">
+                <!-- <el-input
                 v-model="form.content"
                 type="textarea"
                 :rows="2"
                 placeholder="请输入内容"
-              />
-            </el-form-item>
-            <el-form-item label="备注" prop="remark">
-              <el-input
-                v-model="form.remark"
-                placeholder="备注"
-              />
-            </el-form-item>
-            <el-form-item label="排序" prop="sort">
-              <el-input
-                v-model="form.sort"
-                placeholder="排序"
-              />
-            </el-form-item>
-          </el-form>
+              /> -->
+                <rict-text v-model="form.content" />
+              </el-form-item>
+              <el-form-item label="备注" prop="remark">
+                <el-input
+                  v-model="form.remark"
+                  placeholder="备注"
+                />
+              </el-form-item>
+              <el-form-item label="排序" prop="sort">
+                <el-input
+                  v-model="form.sort"
+                  placeholder="排序"
+                />
+              </el-form-item>
+            </el-form>
+          </el-scrollbar>
           <div slot="footer" class="dialog-footer">
             <el-button type="primary" @click="submitForm">确 定</el-button>
             <el-button @click="cancel">取 消</el-button>
@@ -223,10 +225,12 @@ import { addSysContent, delSysContent, getSysContent, listSysContent, updateSysC
 import { listSysCategory } from '@/api/syscategory'
 
 import FileChoose from '@/components/FileChoose'
+import RictText from '@/components/Tinymce'
 export default {
   name: 'Config',
   components: {
-    FileChoose
+    FileChoose,
+    RictText
   },
   data() {
     return {
@@ -374,6 +378,7 @@ export default {
     },
     /** 提交按钮 */
     submitForm: function() {
+      console.log(this.form)
       this.$refs['form'].validate(valid => {
         if (valid) {
           if (this.form.id !== undefined) {