• 若依框架图片上传、富文本框编辑器功能


    一、前言

    现在的需求是:实现一个项目展示模块,后端管理页面除了需要基础信息外,要加上一个图片上传和富文本框编辑器功能

    二、效果

    在这里插入图片描述
    点击”图片存储地址”:可上传电脑任何位置的图片,并可对图片进行放大,缩小,和旋转。

    在这里插入图片描述
    在这里插入图片描述
    存入数据库的图片以url地址存放
    在这里插入图片描述
    url直接百度可看到图片:
    在这里插入图片描述

    三、编码过程

    1.前端:

    index.vue
    <template>
      <div class="app-container">
        
        <el-row :gutter="10" class="mb8">
          <el-col :span="1.5">
            <el-button
              type="primary"
              plain
              icon="el-icon-plus"
              size="mini"
              @click="handleAdd"
              >新增
            el-button>
          el-col>
        el-row>
    
        
        <el-dialog :title="title" :visible.sync="open" width="1000px" append-to-body>
          <el-form ref="formObj" :model="form" :rules="rules" label-width="120px" >
            <el-form-item label="项目名称" prop="projectName">
              <el-input v-model="form.projectName" placeholder="请输入项目名称" />
            el-form-item>
            <el-form-item label="项目类型" prop="projectType">
              <el-select
                v-model="form.projectType"
                placeholder="请选择项目类型"
                style="width: 65%"
              >
                <el-option
                  v-for="dict in projectTypeOptions"
                  :key="dict.dictValue"
                  :label="dict.dictLabel"
                  :value="dict.dictValue"
                >el-option>
              el-select>
            el-form-item>
    
          <el-form-item prop="picUrl" label="图片存储地址"  required>
            <div class="coverImg-upload" @click="showCoverImgCropper = true">
              <img v-if="form.picUrl" :src="form.picUrl" class="coverImg" />
              <i v-else class="el-icon-plus coverImg-upload-icon" />
            div>
          el-form-item>
    
            <el-form-item prop="projectDetail" label="项目详情">
              <my-quill-editor v-model="form.projectDetail" ref="quillEditor" />
            el-form-item>
            <el-form-item label="备注" prop="remark">
              <el-input
                v-model="form.remark"
                type="textarea"
                placeholder="请输入备注"
              />
            el-form-item>
          el-form>
          <img-upload-cropper
          :visible.sync="showCoverImgCropper"
          @upload-success="onCoverImgUploaded"
        />
          <div slot="footer" class="dialog-footer">
            <el-button type="primary" @click="submitForm">确 定el-button>
            <el-button @click="cancel">取 消el-button>
          div>
          
        el-dialog>
    
        
        <el-table
          v-loading="loading"
          :data="projectShowList"
          row-key="id"
          default-expand-all
          :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
        >
          <el-table-column label="项目名称" align="center" prop="projectName" />
          <el-table-column
            label="图片存储地址"
            align="center"
            prop="picUrl"
            v-if="false"
          />
          <el-table-column
            label="项目详情"
            align="center"
            prop="projectDetail"
            v-if="false"
          />
          <el-table-column
            label="项目类型"
            align="center"
            prop="projectType"
            :formatter="projectTypeFormat"
          />
          <el-table-column label="创建人" align="center" prop="createUser" />
          <el-table-column label="创建时间" align="center" prop="createTime" />
          <el-table-column label="修改人" align="center" prop="updateUser" />
          <el-table-column label="修改时间" align="center" prop="updateTime" />
          <el-table-column label="备注" align="center" prop="remark"/>
          <el-table-column
            label="操作"
            align="center"
            class-name="small-padding fixed-width"
          >
            <template slot-scope="scope">
              <el-button
                size="mini"
                type="text"
                icon="el-icon-edit"
                @click="handleUpdate(scope.row)"
                >修改el-button
              >
              <el-button
                size="mini"
                type="text"
                icon="el-icon-delete"
                @click="handleDelete(scope.row)"
                >删除el-button
              >
            template>
          el-table-column>
        el-table>
      div>
    template>
      
      <script>
    import {
      listProjectShow,
      addProjectShow,
      updateProjectShow,
      getProjectShow,
      delProjectShow,
    } from "@/api/projectShow/projectShow";
    import myQuillEditor from "@/components/Editor";
    import ImgUploadCropper from "@/components/ImgUploadCropper";
    
    
    export default {
      name: "cpsp",
      components: {
        myQuillEditor,
        ImgUploadCropper,
      },
      data() {
        return {
          // 遮罩层
          loading: true,
          // 资产分类表格数据
          projectShowList: [],
          //计费方式字典
          projectTypeOptions: [],
          // 弹出层标题
          title: "",
          // 资产分类树选项
          categoryOptions: [],
          // 是否显示弹出层
          open: false,
          // 表单参数
          form: {
            id: null,
            projectName: null,
            projectType: "1",
            picUrl: "",
            projectDetail: "",
            remark: null,
          },
          showCoverImgCropper: false,
          formObj: "",
          // 表单校验
          rules: {
            projectName: [
              { required: true, message: "项目名称不能为空", trigger: "blur" },
            ],
            projectType: [
              { required: true, message: "项目类型不能为空", trigger: "blur" },
            ],
            picUrl: [
              { required: true, trigger: "change", message: "图片存储地址不能为空" },
            ],
          },
        };
      },
      mounted() {
        this.formObj = this.$refs.formObj;
      },
      created() {
        this.getList();
        this.getDicts("project_show_type").then((response) => {
          this.projectTypeOptions = response.data;
        });
      },
      methods: {
        /** 查询资产分类列表 */
        getList() {
          this.loading = true;
          listProjectShow(this.queryParams).then((response) => {
            this.projectShowList = response.data;
            this.loading = false;
          });
        },
        // 项目类型字典翻译
        projectTypeFormat(row, column) {
          return this.selectDictLabel(this.projectTypeOptions, row.projectType);
        },
    
        // 取消按钮
        cancel() {
          this.open = false;
          this.reset();
        },
        // 表单重置
        reset() {
          this.form = {
            id: null,
            projectName: null,
            projectType: "1",
            picUrl: "",
            projectDetail: "",
            remark: null,
          };
          this.resetForm("formObj");
        },
        /** 新增按钮操作 */
        handleAdd() {
          this.reset();
          this.open = true;
          this.title = "添加项目";
        },
        /**
         * 组件封面图片上传
         */
         onCoverImgUploaded(picUrl) {
          this.form.picUrl = picUrl;
          // 清除表单校验红字
          this.formObj.clearValidate("picUrl");
        },
        /** 提交按钮 */
        submitForm() {
          this.$refs["formObj"].validate((valid) => {
            if (valid) {
              if (this.form.id != null) {
                updateProjectShow(this.form).then((response) => {
                  this.msgSuccess("修改成功");
                  this.open = false;
                  this.getList();
                });
              } else {
                addProjectShow(this.form).then((response) => {
                  this.msgSuccess("新增成功");
                  this.open = false;
                  this.getList();
                  console.log(this.form);
                });
              }
            }
          });
        },
        /** 修改按钮操作 */
        handleUpdate(row) {
          this.reset();
          getProjectShow(row.id).then((response) => {
            this.form = response.data;
            this.open = true;
            this.title = "修改项目展示内容";
          });
        },
        /** 删除按钮操作 */
        handleDelete(row) {
          this.$confirm('是否确认删除项目名为"' + row.projectName + '"的数据项?', "警告", {
            confirmButtonText: "确定",
            cancelButtonText: "取消",
            type: "warning",
          })
            .then(function () {
              return delProjectShow(row.id);
            })
            .then(() => {
              this.getList();
              this.msgSuccess("删除成功");
            });
        },
      },
    };
    script>
    <style lang="scss">
      .coverImg-upload {
        margin-top: 10px;
        width: 150px;
        height: 150px;
        border: 1px dashed #d9d9d9;
        border-radius: 6px;
        cursor: pointer;
        position: relative;
        overflow: hidden;
        img {
          width: 100%;
          height: 100%;
        }
        .coverImg-upload-icon {
          font-size: 28px;
          color: #8c939d;
          width: 150px;
          height: 150px;
          line-height: 150px;
          text-align: center;
        }
      }
    style>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    projectShow.js
    import request from '@/utils/request'
    
    // 查询项目展示列表
    export function listProjectShow(query) {
      return request({
        url: '/projectShow/list',
        method: 'get',
        params: query
      })
    }
    // 新增项目展示
    export function addProjectShow(data) {
      return request({
        url: '/projectShow',
        method: 'post',
        data: data
      })
    }
    
    // 修改项目展示
    export function updateProjectShow(data) {
      return request({
        url: '/projectShow',
        method: 'put',
        data: data
      })
    }
    // 点击修改按钮获取到具体cpsp项目的详情
    export function getProjectShow(id) {
      return request({
        url: '/projectShow/' + id,
        method: 'get'
      })
    }
    
    // 删除资产分类
    export function delProjectShow(id) {
      return request({
        url: '/projectShow/' + id,
        method: 'delete'
      })
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    富文本框: Editor/index.vue
    <template>
      <div>
        
        <el-upload
          class="avatar-uploader quill-img"
          :action="uploadImgUrl"
          name="file"
          :headers="headers"
          :show-file-list="false"
          :on-success="quillImgSuccess"
          :on-error="uploadError"
          :before-upload="quillImgBefore"
          accept='.jpg,.jpeg,.png,.gif'
        >el-upload>
    
        
        <quill-editor
          class="editor"
          v-model="content"
          ref="quillEditor"
          :options="editorOption"
          @blur="onEditorBlur($event)"
          @focus="onEditorFocus($event)"
          @change="onEditorChange($event)"
        >quill-editor>
      div>
    template>
    
    <script>
    import { getToken } from '@/utils/auth'
    
    // 工具栏配置
    const toolbarOptions = [
      ["bold", "italic", "underline", "strike"],       // 加粗 斜体 下划线 删除线
      ["blockquote", "code-block"],                    // 引用  代码块
      [{ list: "ordered" }, { list: "bullet" }],       // 有序、无序列表
      [{ indent: "-1" }, { indent: "+1" }],            // 缩进
      [{ size: ["small", false, "large", "huge"] }],   // 字体大小
      [{ header: [1, 2, 3, 4, 5, 6, false] }],         // 标题
      [{ color: [] }, { background: [] }],             // 字体颜色、字体背景颜色
      [{ align: [] }],                                 // 对齐方式
      ["clean"],                                       // 清除文本格式
      ["link", "image", "video"]                       // 链接、图片、视频
    ];
    
    import { quillEditor } from "vue-quill-editor";
    import "quill/dist/quill.core.css";
    import "quill/dist/quill.snow.css";
    import "quill/dist/quill.bubble.css";
    
    export default {
      model: {
        prop: "value",
        event: "change"
      },
      props: {
        /* 编辑器的内容 */
        value: {
          type: String
        },
        /* 图片大小 */
        maxSize: {
          type: Number,
          default: 4000 //kb
        }
      },
      components: { quillEditor },
      data() {
        return {
          content: this.value,
          editorOption: {
            placeholder: "",
            theme: "snow", // or 'bubble'
            placeholder: "请输入内容",
            modules: {
              toolbar: {
                container: toolbarOptions,
                handlers: {
                  image: function(value) {
                    if (value) {
                      // 触发input框选择图片文件
                      document.querySelector(".quill-img input").click();
                    } else {
                      this.quill.format("image", false);
                    }
                  }
                }
              }
            }
          },
          // uploadImgUrl: process.env.VUE_APP_BASE_API + "/common/upload", // 上传的图片服务器地址
          uploadImgUrl: process.env.VUE_APP_BASE_API + "/system/file/upload",
          headers: {
            Authorization: 'Bearer ' + getToken()
          }
        };
      },
      watch: {
        value: function() {
          this.content = this.value;
        }
      },
      methods: {
        onEditorBlur() {
          //失去焦点事件
        },
        onEditorFocus() {
          //获得焦点事件
        },
        onEditorChange() {
          //内容改变事件
          this.$emit("change", this.content);
        },
    
        // 富文本图片上传前
        quillImgBefore(file) {
          let fileType = file.type;
    			if(fileType === 'image/jpeg' || fileType === 'image/png'){
    				return true;
    			}else {
    				this.$message.error('请插入图片类型文件(jpg/jpeg/png)');
    				return false;
    			}
        },
    
        quillImgSuccess(res, file) {
          // res为图片服务器返回的数据
          // 获取富文本组件实例
          let quill = this.$refs.quillEditor.quill;
          // 如果上传成功
          if (res.code == 200) {
            // 获取光标所在位置
            let length = quill.getSelection().index;
            // 插入图片  res.url为服务器返回的图片地址
            quill.insertEmbed(length, "image", res.url);
            // 调整光标到最后
            quill.setSelection(length + 1);
          } else {
            this.$message.error("图片插入失败");
          }
        },
        // 富文本图片上传失败
        uploadError() {
          // loading动画消失
          this.$message.error("图片插入失败");
        }
      }
    };
    script> 
    
    <style>
    .editor {
      line-height: normal !important;
      /* height: 192px; */
    }
    .quill-img {
      display: none;
    }
    .ql-snow .ql-tooltip[data-mode="link"]::before {
      content: "请输入链接地址:";
    }
    .ql-snow .ql-tooltip.ql-editing a.ql-action::after {
      border-right: 0px;
      content: "保存";
      padding-right: 0px;
    }
    
    .ql-snow .ql-tooltip[data-mode="video"]::before {
      content: "请输入视频地址:";
    }
    
    .ql-snow .ql-picker.ql-size .ql-picker-label::before,
    .ql-snow .ql-picker.ql-size .ql-picker-item::before {
      content: "14px";
    }
    .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="small"]::before,
    .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="small"]::before {
      content: "10px";
    }
    .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="large"]::before,
    .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="large"]::before {
      content: "18px";
    }
    .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="huge"]::before,
    .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="huge"]::before {
      content: "32px";
    }
    
    .ql-snow .ql-picker.ql-header .ql-picker-label::before,
    .ql-snow .ql-picker.ql-header .ql-picker-item::before {
      content: "文本";
    }
    .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before,
    .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before {
      content: "标题1";
    }
    .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before,
    .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before {
      content: "标题2";
    }
    .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before,
    .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before {
      content: "标题3";
    }
    .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before,
    .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before {
      content: "标题4";
    }
    .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before,
    .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before {
      content: "标题5";
    }
    .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before,
    .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {
      content: "标题6";
    }
    
    .ql-snow .ql-picker.ql-font .ql-picker-label::before,
    .ql-snow .ql-picker.ql-font .ql-picker-item::before {
      content: "标准字体";
    }
    .ql-snow .ql-picker.ql-font .ql-picker-label[data-value="serif"]::before,
    .ql-snow .ql-picker.ql-font .ql-picker-item[data-value="serif"]::before {
      content: "衬线字体";
    }
    .ql-snow .ql-picker.ql-font .ql-picker-label[data-value="monospace"]::before,
    .ql-snow .ql-picker.ql-font .ql-picker-item[data-value="monospace"]::before {
      content: "等宽字体";
    }
    style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    图片上传:ImgUploadCropper/index.vue
    <template>
      <el-dialog
        class="img-upload-cropper"
        :title="title"
        :visible.sync="show"
        width="800px"
        append-to-body
        @close="onDialogClose"
      >
        <el-row>
          <el-col :xs="24" :md="12" :style="{ height: '350px' }">
            <vue-cropper
              ref="cropper"
              :img="options.img"
              outputType="png"
              :info="true"
              :autoCrop="options.autoCrop"
              :autoCropWidth="options.autoCropWidth"
              :autoCropHeight="options.autoCropHeight"
              :fixedBox="options.fixedBox"
              @realTime="realTime"
            />
          el-col>
          <el-col :xs="24" :md="12" :style="{ height: '350px' }">
            <div
              class="upload-preview"
              :style="`width:${options.autoCropWidth}px;height:${options.autoCropHeight}px;border-radius:${previewBorderRaidus}`"
            >
              <img :src="previews.url" :style="previews.img" />
            div>
          el-col>
        el-row>
        <br />
        <el-row>
          <el-col :lg="2" :md="2">
            <el-upload
              action="#"
              :http-request="httpRequest"
              :show-file-list="false"
              :before-upload="beforeUpload"
            >
              <el-button size="small">
                上传
                <i class="el-icon-upload el-icon--right">i>
              el-button>
            el-upload>
          el-col>
          <el-col :lg="{ span: 1, offset: 2 }" :md="2">
            <el-button
              icon="el-icon-plus"
              size="small"
              @click="changeScale(1)"
            >el-button>
          el-col>
          <el-col :lg="{ span: 1, offset: 1 }" :md="2">
            <el-button
              icon="el-icon-minus"
              size="small"
              @click="changeScale(-1)"
            >el-button>
          el-col>
          <el-col :lg="{ span: 1, offset: 1 }" :md="2">
            <el-button
              icon="el-icon-refresh-left"
              size="small"
              @click="rotateLeft()"
            >el-button>
          el-col>
          <el-col :lg="{ span: 1, offset: 1 }" :md="2">
            <el-button
              icon="el-icon-refresh-right"
              size="small"
              @click="rotateRight()"
            >el-button>
          el-col>
          <el-col :lg="{ span: 2, offset: 6 }" :md="2">
            <el-button type="primary" size="small" @click="uploadImg()"
              >提 交el-button
            >
          el-col>
        el-row>
      el-dialog>
    template>
    
    <script>
    import { VueCropper } from "vue-cropper";
    import { fileUpload } from "@/api/system/upload";
    import { uploadAvatar } from "@/api/system/user";
    
    export default {
      name: "img-upload-cropper",
      components: { VueCropper },
      props: {
        visible: {
          type: Boolean,
          default: false,
        },
        title: {
          type: String,
          default: "",
        },
        compType: {
          type: String,
          default: "",
        },
        /**
         * 右边预览图的border-radius,单位自定
         */
        previewBorderRaidus: {
          type: String,
          default: "",
        },
      },
      computed: {},
      watch: {
        visible(val) {
          this.show = val;
        },
      },
      data() {
        return {
          options: {
            img: "", //裁剪图片的地址
            autoCrop: true, // 是否默认生成截图框
            autoCropWidth: 200, // 默认生成截图框宽度
            autoCropHeight: 200, // 默认生成截图框高度
            fixedBox: true, // 固定截图框大小 不允许改变
          },
          show: false,
          previews: {},
        };
      },
      created() {},
      mounted() {},
      methods: {
        /**
         * 关闭时
         */
        onDialogClose() {
          this.$emit("update:visible", false);
        },
        /**
         * 图片上传之前
         */
        beforeUpload(file) {
          if (file.type.indexOf("image/") == -1) {
            this.msgError("文件格式错误,请上传图片类型,如:JPG,PNG后缀的文件。");
          } else {
            const reader = new FileReader();
            reader.readAsDataURL(file);
            reader.onload = () => {
              this.options.img = reader.result;
            };
          }
        },
        /**
         * 上传到服务器
         */
        uploadImg() {
          this.$refs.cropper.getCropBlob((data) => {
            let formData = new FormData();
    
            if (this.compType === "avatar") {
              // 头像上传
              formData.append("avatarfile", data);
    
              uploadAvatar(formData).then((response) => {
                console.log(
                  "🚀 ~ file: index.vue ~ line 161 ~ uploadAvatar ~ response",
                  response
                );
                if (response.code === 200) {
                  this.show = false;
    
                  this.options.img = "";
                  this.$emit("upload-success", response.imgUrl);
    
                  this.msgSuccess("修改成功");
                }
              });
            } else {
              formData.append("file", data);
    
              fileUpload(formData).then((response) => {
                if (response.code === 200) {
                  // this.$refs.cropper.clearCrop();
    
                  this.show = false;
    
                  this.options.img = "";
    
                  this.$emit("upload-success", response.url);
    
                  this.msgSuccess("上传成功");
                }
              });
            }
          });
        },
        // 向左旋转
        rotateLeft() {
          this.$refs.cropper.rotateLeft();
        },
        // 向右旋转
        rotateRight() {
          this.$refs.cropper.rotateRight();
        },
        // 图片缩放
        changeScale(num) {
          num = num || 1;
          this.$refs.cropper.changeScale(num);
        },
        // 实时预览
        realTime(data) {
          this.previews = data;
        },
        /**
         * 覆盖默认的上传行为,可以自定义上传的实现
         * 留空即可,不写这个的话会有点报错
         */
        httpRequest() {},
      },
    };
    script>
    
    <style lang="scss" scoped>
    .img-upload-cropper {
      .upload-preview {
        position: absolute;
        top: 50%;
        transform: translate(50%, -50%);
        border-radius: 0;
        box-shadow: 0 0 4px #ccc;
        overflow: hidden;
      }
    }
    style>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238

    2.后端:

    实体ProjectShow
    @Data
    public class ProjectShow {
        /** 自增长主键ID */
        private Long id;
    
        /** 项目名称 */
        @NotNull(message = "项目名称不能为空")
        private String projectName;
    
        /** 项目类型*/
        @NotNull(message = "项目类型不能为空")
        private String projectType;
    
        /** 图片路径 */
        @NotNull(message = "图片路径不能为空")
        private String picUrl;
    
        /** 项目详情*/
        @NotNull(message = "项目详情不能为空")
        private String projectDetail;
    
        /** 创建人 */
        @NotNull(message = "创建人不能为空")
        private String createUser;
    
        /** 创建日期  */
        @JsonFormat(pattern = "yyyy-MM-dd")
        private Date createTime;
    
        /** 更新人 */
        private String updateUser;
    
        /** 更新日期  */
        @JsonFormat(pattern = "yyyy-MM-dd")
        private Date updateTime;
    
        /** 备注 */
        private String remark;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    ProjectShowController
    @RestController
    @RequestMapping("/projectShow")
    public class ProjectShowController extends BaseController {
        @Autowired
        private IProjectShowService iProjectShowService;
    
        @GetMapping("/list")
        public AjaxResult list(ProjectShow projectShow) {
            List<ProjectShow> list = iProjectShowService.selectProjectShowList(projectShow);
            return  AjaxResult.success(list);
        }
        @PostMapping
        public AjaxResult add(@RequestBody ProjectShow projectShow) {
            return toAjax(iProjectShowService.insertProjectShow(projectShow));
        }
    
        /**
         * 修改
         */
        @PutMapping
        public AjaxResult edit(@RequestBody ProjectShow projectShow) {
            return toAjax(iProjectShowService.updateProjectShow(projectShow));
        }
    
        /**
         * 点击修改按钮后获项目展示的详细信息
         */
        @GetMapping(value = "/{id}")
        public AjaxResult getInfo(@PathVariable("id") Long id) {
            return AjaxResult.success(iProjectShowService.selectProjectShowById(id));
        }
    
        /**
         * 删除
         */
    
        @DeleteMapping("/{ids}")
        public AjaxResult remove(@PathVariable Long[] ids) {
            return toAjax(iProjectShowService.deleteProjectShowByIds(ids));
        }
    
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    IProjectShowService
    public interface IProjectShowService {
        public List<ProjectShow> selectProjectShowList(ProjectShow projectShow);
    
    
    
        public int insertProjectShow(ProjectShow projectShow);
    
        public int updateProjectShow(ProjectShow projectShow);
    
        public ProjectShow  selectProjectShowById(Long id);
    
        public int deleteProjectShowByIds(Long[] ids);
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    ProjectShowServiceImpl
    @Service
    @Slf4j
    public class ProjectShowServiceImpl  implements IProjectShowService {
        @Autowired
        private ProjectShowMapper projectShowMapper;
    
        @Autowired
        private TokenService tokenService;
    
        @Override
        public List<ProjectShow> selectProjectShowList(ProjectShow projectShow) {
            return projectShowMapper.selectProjectShowList(projectShow);
        }
    
        @Override
        public int insertProjectShow(ProjectShow projectShow) {
            LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
            SysUser user = loginUser.getUser();
            projectShow.setCreateUser(user.getUserName());
            projectShow.setCreateTime(new Date());
            return projectShowMapper.insertProjectShow(projectShow);
        }
    
        @Override
        public int updateProjectShow(ProjectShow projectShow) {
            LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
            SysUser user = loginUser.getUser();
            projectShow.setUpdateUser(user.getUserName());
            projectShow.setUpdateTime(new Date());
            return  projectShowMapper.updateProjectShow(projectShow);
        }
    
        @Override
        public ProjectShow selectProjectShowById(Long id) {
            return projectShowMapper.selectProjectShowById(id);
        }
    
        @Override
        public int deleteProjectShowByIds(Long[] ids) {
            return projectShowMapper.deleteProjectShowByIds(ids);
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    ProjectShowMapper
    @Repository
    public interface ProjectShowMapper {
        public List<ProjectShow> selectProjectShowList(ProjectShow projectShow);
        public List<ProjectShow> selectProjectShowList();
    
        public int insertProjectShow(ProjectShow projectShow);
    
        //修改
        public int updateProjectShow(ProjectShow projectShow);
        public ProjectShow selectProjectShowById(Long id);
    
        public int deleteProjectShowByIds(Long[] ids);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    ProjectShowMapper.xml
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.activate.module.projectshow.mapper.ProjectShowMapper">
    
        <resultMap type="com.activate.module.projectshow.domain.ProjectShow" id="ProjectShowResult">
            <result property="id" column="id"/>
            <result property="projectName" column="project_name"/>
            <result property="projectType" column="project_type"/>
            <result property="picUrl" column="pic_url"/>
            <result property="projectDetail" column="project_detail"/>
            <result property="createUser" column="create_user"/>
            <result property="createTime" column="create_time"/>
            <result property="updateUser" column="update_user"/>
            <result property="updateTime" column="update_time"/>
            <result property="remark" column="remark"/>
        </resultMap>
        <sql id="selectProjectShowVo">
            select id, project_name, project_type, pic_url, project_detail, create_user, create_time ,update_user ,update_time ,remark from project_show
        </sql>
    
        <select id="selectProjectShowList" parameterType="com.activate.module.projectshow.domain.ProjectShow" resultMap="ProjectShowResult">
            <include refid="selectProjectShowVo"/>
        </select>
        <select id="selectProjectShowById" parameterType="Long" resultMap="ProjectShowResult">
            <include refid="selectProjectShowVo"/>
            where id = #{id}
        </select>
    
        <insert id="insertProjectShow" parameterType="com.activate.module.projectshow.domain.ProjectShow" useGeneratedKeys="true"
                keyProperty="id">
            insert into project_show
            <trim prefix="(" suffix=")" suffixOverrides=",">
                <if test="projectName != null and projectName != ''">project_name,</if>
                <if test="projectType != null and projectType != ''">project_type,</if>
                <if test="picUrl != null ">pic_url,</if>
                <if test="projectDetail != null ">project_detail,</if>
                <if test="createUser != null ">create_user,</if>
                <if test="createTime != null ">create_time,</if>
                <if test="updateUser != null ">update_user,</if>
                <if test="updateTime != null ">update_time,</if>
                <if test="remark != null ">remark,</if>
            </trim>
            <trim prefix="values (" suffix=")" suffixOverrides=",">
                <if test="projectName != null and projectName != ''">#{projectName},</if>
                <if test="projectType != null and projectType != ''">#{projectType},</if>
                <if test="picUrl != null">#{picUrl},</if>
                <if test="projectDetail != null">#{projectDetail},</if>
                <if test="createUser != null">#{createUser},</if>
                <if test="createTime != null ">#{createTime},</if>
                <if test="updateUser != null ">#{updateUser},</if>
                <if test="updateTime != null ">#{updateTime},</if>
                <if test="remark != null ">#{remark},</if>
    
            </trim>
        </insert>
    
        <update id="updateProjectShow" parameterType="com.activate.module.projectshow.domain.ProjectShow">
            update project_show
            <trim prefix="SET" suffixOverrides=",">
                <if test="projectName != null and projectName != ''">project_name=#{projectName},</if>
                <if test="projectType != null and projectType != ''">project_type=#{projectType},</if>
                <if test="picUrl != null">pic_url=#{picUrl},</if>
                <if test="projectDetail != null">project_detail=#{projectDetail},</if>
                <if test="createUser != null">create_user=#{createUser},</if>
                <if test="createTime != null ">create_time=#{createTime},</if>
                <if test="updateUser != null ">update_user=#{updateUser},</if>
                <if test="updateTime != null ">update_time=#{updateTime},</if>
                <if test="remark != null ">remark=#{remark},</if>
            </trim>
            where id = #{id}
        </update>
    
        <delete id="deleteProjectShowByIds" parameterType="String">
            delete from project_show where id in
            <foreach item="id" collection="array" open="(" separator="," close=")">
                #{id}
            </foreach>
        </delete>
    </mapper>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
  • 相关阅读:
    Visual Studio 如何把一个解决方案中已经打开的选项页在另一个解决方案中打开
    web前端期末大作业 ——电影主题介绍 你好,李焕英 ——html+css+javascript网页设计实例
    【windows】Windows电脑怎么卸载服务/删除服务?
    【数据结构】排序算法复杂度 及 稳定性分析 【图文详解】
    LeetCode42:接雨水
    Java程序员必会Synchronized底层原理剖析
    方案分享:F5机器人防御助企业应对复杂攻击
    程序员是怎么分享微信二维码的
    Win10 安装 Rational Rose 教程
    mysql 常用命令练习
  • 原文地址:https://blog.csdn.net/someday____/article/details/127982436