先看效果

 

 

 

 废话不多直接上代码,也不墨迹了,代码自己拿去跑,前段代码没什么依赖,可以直接跑起来

注意点

1,:需要安装QRCode 组件,自己百度去

2:需要安装wangEditor富文本编辑器组件,版本5,请上官网自己找教程,找vue版本的,安装很复杂,貌似还有兼容问题,如果有问题在回复我,我用的是ruoyi3.7.0

<template>
  <div class="app-container">

    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
      <el-form-item label="标题" prop="picNm">
        <el-input v-model="queryParams.picNm" size="small" clearable></el-input>
      </el-form-item>

      <el-form-item label="投放时间" prop="releaseTime">
        <el-date-picker clearable size="small"
                        v-model="queryParams.releaseTime"
                        type="date"
                        value-format="yyyy-MM-dd"
        >
        </el-date-picker>
      </el-form-item>

      <el-form-item>
        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
      </el-form-item>
    </el-form>

    <el-form label-width="68px">
      <el-row :gutter="10" class="mb8">
        <el-col :span="1.5">
          <el-button
            type="primary"
            plain
            size="mini"
            @click="handleAdd"
            v-hasPermi="['web:lunbo:list']"
          >新增
          </el-button>
        </el-col>
        <el-col :span="1.5">
          <el-button
            type="success"
            plain
            size="mini"
            :disabled="single"
            @click="handleUpdate"
            v-hasPermi="['web:lunbo:list']"
          >修改
          </el-button>
        </el-col>
        <el-col :span="1.5">
          <el-button
            type="danger"
            plain
            size="mini"
            :disabled="multiple"
            @click="handleDelete"
            v-hasPermi="['web:lunbo:list']"
          >删除
          </el-button>
        </el-col>
        <!--      <el-col :span="1.5">-->
        <!--        <el-button-->
        <!--          type="warning"-->
        <!--          plain-->
        <!--          icon="el-icon-download"-->
        <!--          size="mini"-->
        <!--          :loading="exportLoading"-->
        <!--          @click="handleExport"-->
        <!--          v-hasPermi="['web:lunbo:export']"-->
        <!--        >导出</el-button>-->
        <!--      </el-col>-->
        <!--      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>-->
      </el-row>
    </el-form>

    <el-table border v-loading="loading" :data="lunboList" @selection-change="handleSelectionChange">
      <el-table-column type="selection" width="55" align="center"/>
      <!--      <el-table-column label="id" align="center" prop="id" />-->
      <el-table-column label="标题" align="left" prop="picNm" :show-overflow-tooltip="true"/>
      <!--      <el-table-column label="图片地址" align="center" prop="picAddr" />-->


      <el-table-column label="封面图片" align="center" prop="picAddr" width="150">
        <template slot-scope="scope">
          <el-image
            style="height: 35px;padding: 0"
            fit="fill"
            :src="conf.imgUrlDeal(scope.row.picAddr)"
          >
          </el-image>
        </template>
      </el-table-column>

      <el-table-column label="描述" align="left" prop="picDesc" width="160" :show-overflow-tooltip="true"/>

      <el-table-column label="是否展示" align="center" prop="picShow" width="110">
        <template slot-scope="scope">

          <el-switch
            class="switch"
            v-model="scope.row.picShow"
            :validate-event="true"
            active-text="显示"
            inactive-text="隐藏"
            active-value="0"
            inactive-value="1"
            @change="isShowTypeChange(scope.row)"
          />

        </template>
      </el-table-column>

      <el-table-column label="广告链接" align="left" prop="picHyperlink" :show-overflow-tooltip="true">
        <template slot-scope="scope">
          <span @click="conf.openIframe(scope.row.picHyperlink,show,urlItem)">
              <el-link type="primary" style="font-size: 11px" target="_blank">{{ scope.row.picHyperlink }}</el-link>
          </span>
        </template>
      </el-table-column>

      <!--      <el-table-column label="创建人" align="center" prop="creater" />-->
      <!--      <el-table-column label="创建时间" align="center" prop="createDt" width="180">-->
      <!--        <template slot-scope="scope">-->
      <!--          <span>{{ parseTime(scope.row.createDt, '{y}-{m}-{d}') }}</span>-->
      <!--        </template>-->
      <!--      </el-table-column>-->
      <el-table-column label="更新人" align="center" prop="modifier" width="90"/>
      <el-table-column label="更新时间" align="center" prop="modifyDt" width="125">
        <template slot-scope="scope">
          <span>{{ parseTime(scope.row.modifyDt, '{y}-{m}-{d}') }}</span>
        </template>
      </el-table-column>

      <el-table-column label="投放开始时间" align="center" prop="modifyDt" width="125">
        <template slot-scope="scope">
          <span>{{ parseTime(scope.row.releaseTime, '{y}-{m}-{d}') }}</span>
        </template>
      </el-table-column>
      <el-table-column label="投放结束时间" align="center" prop="modifyDt" width="125">
        <template slot-scope="scope">
          <span>{{ parseTime(scope.row.lockTime, '{y}-{m}-{d}') }}</span>
        </template>
      </el-table-column>

      <!--      <el-table-column label="备注" align="center" prop="remarks" width="200"/>-->
      <!--      <el-table-column label="图片超链接" align="center" prop="picHyperlink" />-->
      <!--      <el-table-column label="广告类型" align="center" prop="adType" />-->
      <!--      <el-table-column label="倒计时" align="center" prop="countdown" />-->
      <!--      <el-table-column label="倒计时" align="center" prop="savepic" />-->
      <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="160">
        <template slot-scope="scope">

          <el-button slot="reference" size="mini" type="text"
                     @click="creatQrCode(scope.row.picHyperlink)"
          > 预览
          </el-button>

          <el-button
            size="mini"
            type="text"
            icon="el-icon-edit"
            @click="handleUpdate(scope.row)"
            v-hasPermi="['web:lunbo:list']"
          >修改
          </el-button>
          <el-button
            size="mini"
            type="text"
            icon="el-icon-delete"
            @click="handleDelete(scope.row)"
            v-hasPermi="['web:lunbo:list']"
          >删除
          </el-button>
        </template>
      </el-table-column>
    </el-table>

    <pagination
      v-show="total>0"
      :total="total"
      :page.sync="queryParams.pageNum"
      :limit.sync="queryParams.pageSize"
      @pagination="getList"
    />

    <!-- 添加或修改广告轮播图对话框 -->
    <el-dialog :title="title" :visible.sync="open" width="1000px" append-to-body>
      <el-form :inline="true" ref="form" :model="form" :rules="rules" label-width="100px">

        <el-row>
          <el-col :span="12">
            <el-form-item label="标题" prop="picNm">
              <el-input style="width: 360px" @change="updateRichHtml" v-model="form.picNm"/>
            </el-form-item>

            <el-form-item label="描述" prop="picDesc">
              <el-input style="width: 360px" v-model="form.picDesc"/>
            </el-form-item>

            <el-form-item label="是否显示" prop="picShow">
              <el-checkbox-group v-model="form.picShow"
                                 @change="((val)=> {
                                   form.picShow = (val == 'null' || !val) ? nextItem.picShow : val;
                                   nextItem.picShow = form.picShow;

                                 })"
              >
                <el-checkbox false-label="null" true-label="0">显示</el-checkbox>
                <el-checkbox false-label="null" true-label="1">隐藏</el-checkbox>
              </el-checkbox-group>
            </el-form-item>

            <!--            <el-form-item label="创建时间" prop="createDt">-->
            <!--              <el-date-picker clearable size="small"-->
            <!--                              disabled="disabled"-->
            <!--                              v-model="form.createDt"-->
            <!--                              type="date"-->
            <!--                              style="width: 360px"-->
            <!--                              value-format="yyyy-MM-dd">-->
            <!--              </el-date-picker>-->
            <!--            </el-form-item>-->

            <!--            <el-form-item label="修改时间" prop="modifyDt">-->
            <!--              <el-date-picker clearable size="small"-->
            <!--                              v-model="form.modifyDt"-->
            <!--                              type="date"-->
            <!--                              style="width: 360px"-->
            <!--                              disabled="disabled"-->
            <!--                              value-format="yyyy-MM-dd">-->
            <!--              </el-date-picker>-->
            <!--            </el-form-item>-->

            <el-form-item label="网页类型" prop="pageType">
              <el-checkbox-group v-model="form.pageType"
                                 @change="((val)=> {
                                 form.pageType = (val == 'null' || !val) ? nextItem.pageType : val;
                                 nextItem.pageType = form.pageType;
                                 show.richText = form.pageType == '0'
                               })"
              >
                <el-checkbox false-label="null" true-label="1">第三方</el-checkbox>
                <el-checkbox false-label="null" true-label="0">本地页面</el-checkbox>
              </el-checkbox-group>
            </el-form-item>

          </el-col>

          <el-col :span="12">
            <el-form-item label="封面图片" prop="picAddr">
              <div class="avatar-uploader">
                <el-upload style="width: 360px" action="#" accept=".jpg,.png,.jpeg" :http-request="requestUpload"
                           :show-file-list="false"
                           :before-upload="beforeUpload"
                >

                  <!-- 如果有地址,会有两种情况,一种是新增时添加的图片,一种是点击编辑查询后存在 -->
                  <el-image v-if="form.picNmFile" fit="contain" style="max-width: 100%" :src="form.picAddr"
                            class="avatar"
                  />
                  <!-- 因此采用了代理,所以只需要吧圖片地址加上api路徑拼接上去就行了 -->
                  <el-image v-else-if="form.picAddr" fit="contain" style="max-width: 100%" :src="baseUrl + form.picAddr"
                            class="avatar"
                  />
                  <i v-else class="el-icon-plus avatar-uploader-icon"></i>
                </el-upload>
                <span style="color: #999999;font-size: 11px">{{ routeQueryParms.picstr }}</span>
              </div>
            </el-form-item>
          </el-col>
        </el-row>

        <el-row>
          <el-col :span="12">
            <el-form-item label="跳转链接" prop="picHyperlink">
              <el-input type="textarea" style="width: 360px" v-model="form.picHyperlink"/>
            </el-form-item>
          </el-col>


          <el-col :span="12">
            <el-form-item label="备注" prop="remarks">
              <el-input v-model="form.remarks" style="width: 360px" type="textarea"></el-input>
            </el-form-item>
          </el-col>
        </el-row>

        <el-row>

          <el-col :span="12">
            <el-form-item label="发布时间" prop="releaseTime">
              <el-date-picker
                style="width: 360px"
                size="small"
                value-format="yyyy-MM-dd HH:mm:ss"
                v-model="form.releaseTime"
                type="daterange"
                align="right"
                unlink-panels
                range-separator="至"
                start-placeholder="发布时间"
                end-placeholder="截止时间"
                :picker-options="conf.pickerOptions"
              >
              </el-date-picker>
            </el-form-item>
          </el-col>
        </el-row>
        <!--        <el-form-item label="广告类型" prop="adType">-->
        <!--          <el-select v-model="form.adType" placeholder="请选择广告类型">-->
        <!--            <el-option label="请选择字典生成" value="" />-->
        <!--          </el-select>-->
        <!--        </el-form-item>-->


        <!--        <el-form-item label=""  label-width="100px">-->
        <div style="display: flex;justify-content: space-between" v-show="show.richText">
          <div style="width: 100px;text-align: right;padding-right: 15px">
            网页内容
          </div>
          <div style="border: 1px solid #ccc;width: 98%;z-index: 9999">
            <Toolbar
              class="toolbar_1"
              :editor="editorItem.editor"
              :defaultConfig="editorItem.toolbarConfig"
              :mode="editorItem.mode"
            />
            <!--            v-model="editorItem.html"-->

            <Editor
              ref="editor"
              style="height:410px; overflow-y: scroll;width: 100%;background-color:white;"
              v-model="form.richText"
              :defaultConfig="editorItem.editorConfig"
              :mode="editorItem.mode"
              @onCreated="onCreated"
            />
          </div>
        </div>
        <!--        </el-form-item>-->


        <!--        <el-form-item label="倒计时" prop="countdown">-->
        <!--          <el-input v-model="form.countdown" placeholder="请输入倒计时" />-->
        <!--        </el-form-item>-->


      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="submitForm">确 定</el-button>
        <el-button @click="cancel">取 消</el-button>
      </div>
    </el-dialog>

    <el-dialog
      title="扫码预览"
      :visible.sync="show.qrCode"
      width="400px"
      top="50vh"
    >
      <div style="display: flex;justify-content: center;">
        <div class="qrcode" ref="qrcode"></div>
      </div>
      <!--      :before-close="handleClose">-->
    </el-dialog>

    <el-dialog
      title="预览网页"
      :visible.sync="show.html"
      width="500px"
      height="950px"
      @close="()=>{urlItem.htmlUrl = null}"
    >
      <div style="display: flex;justify-content: center;">

        <iframe :src="urlItem.htmlUrl" height="800" width="550" title="广告预览" frameborder="0"></iframe>

      </div>
      <!--      :before-close="handleClose">-->
    </el-dialog>

  </div>

</template>

<script>
import { listLunbo, getLunbo, delLunbo, addLunbo, updateLunbo, exportLunbo, picShowUpdate } from '@/api/gzApi/lunbo'
// import { getToken } from '@/utils/auth'
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
import '@wangeditor/editor/dist/css/style.css'
import editorConfig from '@/utils/wangEditor'
import { pickerOptions, openIframe, imgUrlDeal, getNowDate } from '@/utils/elementuiConf'
import { DomEditor } from '@wangeditor/editor'
// 配置编辑器是否支持滚动,默认为 true
import QRCode from 'qrcodejs2'

export default {
  // dom中的editor
  components: { Editor, Toolbar },
  dicts: ['isok'],
  name: 'Lunbo',
  data() {
    return {
      urlItem: {
        htmlUrl: null
      },
      conf: {
        pickerOptions: pickerOptions,
        openIframe: openIframe,
        imgUrlDeal: imgUrlDeal
      },
      show: {
        richText: false,
        qrCode: false,
        html: false
      },
      nextItem: {
        picShow: null,
        pageType: '1',
        contentTitle: '{#标题#}'
      },
      editorItem: {
        editor: null,
        html: '',
        // 工具栏配置
        // toolbarConfig:,
        editorConfig: editorConfig,
        mode: 'default' // or 'simple'
      },
      // headerObj: {
      //   Authorization: 'Bearer ' + getToken()
      // },
      routeQueryParms: {},
      // 后台地址
      baseUrl: process.env.VUE_APP_BASE_API,
      // 遮罩层
      loading: true,
      // 导出遮罩层
      exportLoading: false,
      // 选中数组
      ids: [],
      picNms: [],
      // 非单个禁用
      single: true,
      // 非多个禁用
      multiple: true,
      // 显示搜索条件
      showSearch: true,
      // 总条数
      total: 0,
      // 广告轮播图表格数据
      lunboList: [],
      // 弹出层标题
      title: '',
      // 是否显示弹出层
      open: false,
      // 查询参数
      queryParams: {
        pageNum: 1,
        pageSize: 10,
        picShow: null,
        adType: null,
        pageType: null,
        picNm: null,
        releaseTime: null
      },
      // 表单参数
      form: { pageType: '1' },
      // 表单校验
      rules: {
        picNm: [
          { required: true, message: '标题不能为空', trigger: 'blur' }
        ],
        releaseTime: [
          { required: true, message: '请选择发布时间', trigger: 'blur' }
        ],
        picAddr: [
          { required: true, message: '请添加图片', trigger: 'blur' },
          {
            validator: (rule, value, callback) => {
              if (!this.form.picAddr) {
                return callback(new Error('请添加图片'))
              } else {
                callback()
              }
            },
            trigger: ['blur', 'change']
          }
        ],
        picDesc: [
          { required: true, message: '描述不能为空', trigger: 'blur' }
        ]
      }
    }
  },
  beforeDestroy() {
    const editor = this.editorItem.editor
    if (editor == null) return
    editor.destroy() // 组件销毁时,及时销毁编辑器
  },
  mounted() {
  },
  created() {
    const query = this.$route.query
    this.routeQueryParms = query
    this.getList()
  },
  methods: {
    isShowTypeChange(row) {
      this.$modal.confirm('是否' + (row.picShow == '0' ? '展示' : '隐藏') + '标题为"' + row.picNm + '"的数据项?').then(function() {
        return picShowUpdate({ id: row.id, picShow: row.picShow })
      }).then(() => {
        this.getList()
        this.$modal.msgSuccess('操作成功!')
      }).catch(function() {
        // 00 隐藏,01不隐藏
        row.picShow = (row.picShow === '0' ? '1' : '0')
      })
    },
    // 二维码方法
    creatQrCode(url) {
      this.$set(this.show, 'qrCode', true)
      this.$nextTick(() => {
        this.$refs.qrcode.innerHTML = ''
        const qrcode = new QRCode(this.$refs.qrcode, {
          text: url, // 需要转换为二维码的内容
          width: 180,
          height: 180,
          colorDark: '#000000',
          colorLight: '#ffffff',
          correctLevel: QRCode.CorrectLevel.H
        })
      })
    },

    onCreated(editor) {
      this.editorItem.editor = Object.seal(editor) // 一定要用 Object.seal() ,否则会报错
    },
    // 覆盖默认的上传行为
    requestUpload() {
    },
    beforeUpload(file) {
      const isLt2M = file.size / 1024 / 1024 < 2
      if (!isLt2M) {
        this.$message.error('图片大小不能超过2MB!')
        return
      }
      if (file.type.indexOf('image/') == -1) {
        this.$modal.msgError('文件格式错误,请上传图片类型,如:JPG,PNG后缀的文件。')
      } else {
        const reader = new FileReader()
        reader.readAsDataURL(file)
        reader.onload = () => {
          // 这个是要上传的真实图片文件
          this.form.picNmFile = file
          // 此时图片是base64编码文件
          this.form.picAddr = reader.result
          this.$refs.form.validateField('picAddr')
        }
      }
    },

    /** 查询广告轮播图列表 */
    getList() {
      this.loading = true
      listLunbo(this.queryParams).then(response => {
        this.lunboList = response.rows
        this.total = response.total
        this.loading = false
      })
    },
    // 取消按钮
    cancel() {
      this.open = false
      this.reset()
    },
    // 表单重置
    reset() {
      this.form = {
        id: null,
        picNm: null,
        picAddr: null,  // 新增的时候是base64编码字节数据,但是只有在file不为空的时候才会提交
        picDesc: null,
        picShow: '0',
        creater: null,
        createDt: null,
        modifier: null,
        modifyDt: null,
        remarks: null,
        deleteFlag: null,
        picHyperlink: null,
        adType: null,
        pageType: '1', // 默认外部网页链接
        countdown: null,
        savepic: null,
        picNmFile: null, // 图片文件
        richText: '', // 富文本
        releaseTime: null,
        lockTime: null
      }
      this.show = {
        richText: false
      }
      this.resetForm('form')
    },
    /** 搜索按钮操作 */
    handleQuery() {
      this.queryParams.pageNum = 1
      this.getList()
    },
    /** 重置按钮操作 */
    resetQuery() {
      this.resetForm('queryForm')
      this.handleQuery()
    },
    // 多选框选中数据
    handleSelectionChange(selection) {
      this.ids = selection.map(item => item.id)
      this.picNms = selection.map(item => item.picNm)
      this.single = selection.length !== 1
      this.multiple = !selection.length
    },
    /** 新增按钮操作 */
    handleAdd() {
      this.reset()
      this.open = true
      this.title = '添加广告轮播图'

      // 清除富文本内容
      // if (this.editorItem.editor) {
      //   this.editorItem.editor.clear();
      //   this.editorItem.editor.setHtml('<p></p>')
      // }

      this.nextItem.contentTitle = '{#标题#}'

      this.$set(this.form, 'richText',
        '<h1>' +
        '<span style="font-size: 22px;line-height: 44px;padding: 1px 0;text-align: left;font-weight: normal;">' + this.nextItem.contentTitle  + '</span>' +
        '</h1>'+
        '<p>' +
        '<span style="line-height: 24px;color: rgb(153, 153, 153); background-color: rgb(255, 255, 255); font-size: 12px;">运营  ' + getNowDate() + '</span>' +
        '</p>'
      )

    },

    // 更新富文本中的标题
    updateRichHtml(val) {
      // 富文本内容
      let richText = this.form.richText
      // 占位符
      let contentTitle = this.nextItem.contentTitle

      // 如果不为初始值,那么就截取,真实值,方便替换富文本内容
      if ('{#标题#}' !== contentTitle) {
        contentTitle = contentTitle.replace('{#', '').replace('#}', '')
      }

      // 将标题替换进内容中
      const newHtml = richText.replace(contentTitle, val)
      this.$set(this.form, 'richText', newHtml)
      this.nextItem.contentTitle = '{#' + val + '#}'
    },

    /** 修改按钮操作 */
    handleUpdate(row) {
      this.reset()
      const id = row.id || this.ids
      getLunbo(id).then(response => {
        // 初始化发布时间
        if (response.data.releaseTime) {
          response.data.releaseTime = [response.data.releaseTime, response.data.lockTime]
        }

        this.form = response.data
        // 如果是本地连接则打开富文本编辑器,否则则关闭
        this.show.richText = this.form.pageType === '0'

        // 写入富文本内容
        this.$nextTick(() => {
          if (this.editorItem.editor) {
            this.editorItem.editor.clear()
            this.editorItem.editor.setHtml(this.form.richText)
          }
        })

        this.open = true
        this.title = '修改广告轮播图'
      })
    },
    /** 提交按钮 */
    submitForm() {
      this.$refs['form'].validate(valid => {
        let fd = new FormData()
        fd.append('id', this.form.id ? this.form.id : '')
        fd.append('picNm', this.form.picNm ? this.form.picNm : '')

        // 图片文件存在才去拼接
        if (this.form.picNmFile) {
          fd.append('picNmFile', this.form.picNmFile, this.form.picNmFile.name)
        }

        fd.append('picHyperlink', this.form.picHyperlink ? this.form.picHyperlink : '')
        fd.append('remarks', this.form.remarks ? this.form.remarks : '')
        fd.append('picDesc', this.form.picDesc ? this.form.picDesc : '')
        fd.append('picShow', this.form.picShow ? this.form.picShow : '')
        fd.append('createDt', this.form.createDt ? this.form.createDt : '')
        fd.append('modifyDt', this.form.modifyDt ? this.form.modifyDt : '')
        fd.append('pageType', this.form.pageType ? this.form.pageType : '')
        fd.append('richText', this.form.richText ? this.form.richText : '')

        // 发布时间
        if (this.form.releaseTime) {
          fd.append('lockTime', this.form.releaseTime ? this.form.releaseTime[1] : '')
          fd.append('releaseTime', this.form.releaseTime ? this.form.releaseTime[0] : '')
        }

        if (valid) {
          if (this.form.id != null) {
            updateLunbo(fd).then(response => {
              this.$modal.msgSuccess('修改成功')
              this.open = false
              this.getList()
            })
          } else {
            addLunbo(fd).then(response => {
              this.$modal.msgSuccess('新增成功')
              this.open = false
              this.getList()
            })
          }
        }

      })
    },
    /** 删除按钮操作 */
    handleDelete(row) {
      const ids = row.id || this.ids
      const names = row.picNm || this.picNms

      this.$modal.confirm('是否删除广告图标题为"' + names + '"的数据项?').then(function() {
        return delLunbo(ids)
      }).then(() => {
        this.getList()
        this.$modal.msgSuccess('删除成功')
      }).catch(() => {
      })
    },
    /** 导出按钮操作 */
    handleExport() {
      const queryParams = this.queryParams
      this.$modal.confirm('是否确认导出所有广告轮播图数据项?').then(() => {
        this.exportLoading = true
        return exportLunbo(queryParams)
      }).then(response => {
        this.$download.name(response.msg)
        this.exportLoading = false
      }).catch(() => {
      })
    }
  }
}
</script>
<style scoped>
/*src="@wangeditor/editor/dist/css/style.css"*/
.avatar-uploader .el-upload {
  border: 1px dashed #d9d9d9 !important;
  border-radius: 6px !important;
  cursor: pointer !important;
  position: relative !important;
  overflow: hidden !important;
}

.avatar-uploader .el-upload:hover {
  border-color: #409EFF !important;
}

.avatar-uploader-icon {
  font-size: 34px !important;
  color: #8c939d !important;
  width: 350px !important;
  height: 180px !important;
  line-height: 180px !important;
  text-align: center !important;
  border: 1px #d9d9d9 solid !important;
}

.avatar {
  /*width: 200px;*/
  height: 180px !important;
  /*display: block;*/
}

.el-form-item--medium .el-form-item__content {
  line-height: 0 !important;
}

::v-deep .toolbar_1 .title {
  font-size: 10px;
  margin: 0;
  text-align: center;
}

.toolbar_1 {
  border-bottom: 1px solid #ccc;
}


/* switch按钮样式 */
::v-deep .switch .el-switch__label {
  position: absolute;
  display: none;
  color: #fff !important;
}

/*打开时文字位置设置*/
::v-deep .switch .el-switch__label--right {
  z-index: 1;
}

/* 调整打开时文字的显示位子 */
::v-deep .switch .el-switch__label--right span {
  margin-right: 9px;
}

/*关闭时文字位置设置*/
::v-deep .switch .el-switch__label--left {
  z-index: 1;
}

/* 调整关闭时文字的显示位子 */
::v-deep .switch .el-switch__label--left span {
  margin-left: 9px;
}

/*显示文字*/
::v-deep .switch .el-switch__label.is-active {
  display: block;
}

/* 调整按钮的宽度 */
::v-deep .switch.el-switch .el-switch__core,
::v-deep .el-switch .el-switch__label {
  width: 70px !important;
  margin: 0;
}
/*::v-deep .w-e-text-container .w-e-modal :first-child label:nth-of-type(3){*/
/*  background-color: #00afff;*/
/*  display: none;*/
/*}*/
::v-deep  video{
  max-width: 100%;
}
</style>

第二步,补齐配置文件

上述vue组件中使用到的wangEditor.js配置,请依据引入的路径创建本文件
import { getToken } from '@/utils/auth'
// import resize from "../views/dashboard/mixins/resize";
import { uploadFileHce } from '../api/common'
import { Message } from 'element-ui'

export default {
  // menus: [
  //   // "head",
  //   'bold',
  //   'fontSize',
  //   "fontName",
  //   'italic',
  //   'underline',
  //   '|',
  //   'strikeThrough',
  //   'indent',
  //   'lineHeight',
  //   'foreColor',
  //   'backColor',
  //   'link',
  //   '|',
  //   'list',
  //   // "todo",
  //   'image',
  //   'justify',
  //   'quote',
  //   'table',
  //   '|',
  //   'code',
  //   'splitLine',
  //   'undo',
  //   'emoticon',
  //   'redo'
  // ],
  placeholder: '请输入内容...',
  scroll: false,
  // autoFocus:true,
  MENU_CONF: {
    // emotion:{
    //   emotions: '😀 😃 😄 😁 😆 😅 😂 🤣 😊 😇 🙂 🙃 😉'.split(' ') // 数组
    // }
    // fontFamily: {
    //   fontFamilyList: [
    //     // 元素支持两种形式
    //     //   1. 字符串;
    //     //   2. { name: 'xxx', value: 'xxx' }
    //
    //     '黑体',
    //     '楷体',
    //     { name: '仿宋', value: '仿宋' },
    //     'Arial',
    //     'Tahoma',
    //     'Verdana'
    //   ]
    // },
    // 上传图片的配置
    uploadImage: {

      server: process.env.VUE_APP_BASE_API + '/common/editorUpload/hce',

      // 字段名称
      fieldName: 'file',

      // 单个文件的最大体积限制,默认为 2M
      maxFileSize: 4 * 1024 * 1024, // 1M

      // 最多可上传几个文件,默认为 100
      maxNumberOfFiles: 20,

      // 选择文件时的类型限制,默认为 ['image/*'] 。如不想限制,则设置为 []
      allowedFileTypes: ['image/*'],

      base64LimitSize: 75 * 1024, // 100kb 以下插入 base64

      // 自定义上传参数,例如传递验证的 token 等。参数会被添加到 formData 中,一起上传到服务端。
      meta: {
        type: 'img'
      },

      // 将 meta 拼接到 url 参数中,默认 false
      metaWithUrl: false,

      // 自定义增加 http  header
      headers: {
        // Accept: 'text/x-json',
        Authorization: 'Bearer ' + getToken()
      },

      // 跨域是否传递 cookie ,默认为 false
      withCredentials: false,

      // 超时时间,默认为 10 秒
      timeout: 5 * 1000, // 5 秒

      onBeforeUpload(files) {
        return files // 返回哪些文件可以上传
        // return false 会阻止上传
      },

      // 上传进度的回调函数
      onProgress(progress) {
        // console.log("onProgress", progress);
      },
      // 单个文件上传成功之后
      onSuccess(file, res) {
        Message({
          message: '上传成功',
          type: 'success'
        })
        // console.log("onSuccess", file, res);
      },
      // 单个文件上传失败
      onFailed(file, res) {
        Message({
          message: res.msg ? res.msg : '文件上传失败,可能是网络原因',
          type: 'error'
        })
        // console.log("onFailed", file, res);
      },
      // 上传错误,或者触发 timeout 超时
      onError(file, err, res) {
        Message({
          message: res.msg ? res.msg : '文件上传时发送错误,可能是网络原因,请检查!',
          type: 'error'
        })
      }

      // 用户自定义上传图片
      // customUpload(file, insertFn) {
      //   const data = new FormData();
      //   data.append("file", file); // file 即选中的文件
      //   // data.append("type", 'img'); // file
      //
      //   uploadFileHce(data).then(res => {
      //     // 这个返回的是相对路径
      //     let url = res.fileName;
      //     // baseapi进行拼接
      //     url = process.env.VUE_APP_BASE_API + url;
      //     insertFn(url, '', res.fileName); //插入图片
      //   })
      // }

    },
    // 上传视频的配置
    uploadVideo: {
      server: process.env.VUE_APP_BASE_API + '/common/editorUpload/hce',
      fieldName: 'file',
      // 单个文件的最大体积限制,默认为 10M, 现在是20M
      maxFileSize: 200 * 1024 * 1024, // 5M
      // 最多可上传几个文件,默认为 5
      maxNumberOfFiles: 3,
      // 选择文件时的类型限制,默认为 ['video/*'] 。如不想限制,则设置为 []
      allowedFileTypes: ['video/*'],
      //  将 meta 拼接到 url 参数中,默认 false
      metaWithUrl: false,
      meta: {
        type: 'video'
      },
      // // 自定义增加 http  header
      headers: {
        Authorization: 'Bearer ' + getToken()
      },
      // // 跨域是否传递 cookie ,默认为 false
      withCredentials: false,
      // // 超时时间,默认为 30 秒
      timeout: 21 * 1000, // 15 秒

      // 上传之前触发
      onBeforeUpload(file) {
        return file
      },

      // 上传进度的回调函数
      onProgress(progress) {
        // console.log("onProgress", progress);
      },
      // 单个文件上传成功之后
      onSuccess(file, res) {
        Message({
          message: '上传成功',
          type: 'success'
        })
        // console.log("onSuccess", file, res);
      },
      // 单个文件上传失败
      onFailed(file, res) {
        Message({
          message: res.msg ? res.msg : '文件上传失败,可能是网络原因',
          type: 'error'
        })
        // console.log("onFailed", file, res);
      },
      // 上传错误,或者触发 timeout 超时
      onError(file, err, res) {
        Message({
          message: res.msg ? res.msg : '文件上传时发送错误,可能是网络原因,请检查!',
          type: 'error'
        })
      }

      // 用户自定义上传视频
      // customUpload(file, insertFn) {
      //   const data = new FormData();
      //   data.append("file", file); // file 即选中的文件
      //   data.append("type", 'video'); // file 即选中的文件
      //
      //   uploadFileHce(data).then(res => {
      //     // 这个返回的是相对路径
      //     let url = res.fileName;
      //     // baseapi进行拼接
      //     url = process.env.VUE_APP_BASE_API + url;
      //     insertFn(url, '', res.fileName); //插入图片
      //   })
      // }

    }

  }
}

第三步,创建公共配置elementuiConf.js,依据vue引入路径创建

// elementui配置
// 日期选择配置
import QRCode from "qrcodejs2";

export const pickerOptions = {
  shortcuts: [{
    text: '未来一周',
    onClick(picker) {
      let start = getNowDate_01();
      let end = getNowDate_01();

      end.setTime(end.getTime() + 3600 * 1000 * 24 * 7);
      picker.$emit('pick', [start, end]);
    }
  }, {
    text: '未来一个月',
    onClick(picker) {
      let start = getNowDate_01();
      let end = getNowDate_01();
      end.setTime(end.getTime() + 3600 * 1000 * 24 * 30);
      picker.$emit('pick', [start, end]);
    }
  }, {
    text: '未来三个月',
    onClick(picker) {
      let start = getNowDate_01();
      let end = getNowDate_01();
      end.setTime(end.getTime() + 3600 * 1000 * 24 * 90);
      picker.$emit('pick', [start, end]);
    }
  }, {
    text: '未来半年',
    onClick(picker) {
      let start = getNowDate_01();
      let end = getNowDate_01();
      end.setTime(end.getTime() + 3600 * 1000 * 24 * 180);
      picker.$emit('pick', [start, end]);
    }
  }, {
    text: '未来一年',
    onClick(picker) {
      let start = getNowDate_01();
      let end = getNowDate_01();
      end.setTime(end.getTime() + 3600 * 1000 * 24 * 365);
      picker.$emit('pick', [start, end]);
    }
  }, {
    text: '未来两年',
    onClick(picker) {
      let start = getNowDate_01();
      let end = getNowDate_01();
      end.setTime(end.getTime() + 3600 * 1000 * 24 * 365 * 2);
      picker.$emit('pick', [start, end]);
    }
  }, {
    text: '未来五年',
    onClick(picker) {
      let start = getNowDate_01();
      let end = getNowDate_01();
      end.setTime(end.getTime() + 3600 * 1000 * 24 * 365 * 5);
      picker.$emit('pick', [start, end]);
    }
  }],

  //禁用当前日期之前的日期
  // disabledDate(time) {
  //   //Date.now()是javascript中的内置函数,它返回自1970年1月1日00:00:00 UTC以来经过的毫秒数。
  //   return time.getTime() < Date.now() - 8.64e7;
  // }
}

// 打开网页预览
export function openIframe(url, show, urlItem) {
  // 判断是否需要打开新的ifrema还是在本页面打开
  if ((url.indexOf("app.urumqimtr.com") > -1) || (url.indexOf("localhost:") > -1)) {
    show.html = true;
    urlItem.htmlUrl = url;
  } else {
    window.open(url);
  }
}

// 获取图片地址,有的图片是网络图片。有的图片是本地图片,尽量都能展示
export function imgUrlDeal(url) {
  if (url) {
    // 以/为开头说明是本地服务器图片
    if (url.startsWith("/")) {
      return process.env.VUE_APP_BASE_API + url
    }
    return url;
  } else {
    return null;
  }

}

// 格式化日年月日
export function getNowDate_01() {
  let date = new Date();
  let year = date.getFullYear() // 年
  let month = date.getMonth() + 1; // 月
  let day = date.getDate(); // 日

  // 给一位数的数据前面加 “0”
  if (month >= 1 && month <= 9) {
    month = "0" + month;
  }
  if (day >= 0 && day <= 9) {
    day = "0" + day;
  }

  let time = year + "-" + month + "-" + day;
  time = time.replace(new RegExp(/-/gm), '/').replace('T', ' ').replace(new RegExp(/\.[\d]{3}/gm),'');
  date = new Date(time);
  return date;
}

// 格式化日对象
export function getNowDate() {
  let date = new Date();
  let sign2 = ":";
  let year = date.getFullYear() // 年
  let month = date.getMonth() + 1; // 月
  let day = date.getDate(); // 日
  let hour = date.getHours(); // 时
  let minutes = date.getMinutes(); // 分
  let seconds = date.getSeconds() //秒
  const weekArr = ['星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期天'];
  const week = weekArr[date.getDay()];
  // 给一位数的数据前面加 “0”
  if (month >= 1 && month <= 9) {
    month = "0" + month;
  }
  if (day >= 0 && day <= 9) {
    day = "0" + day;
  }
  if (hour >= 0 && hour <= 9) {
    hour = "0" + hour;
  }
  if (minutes >= 0 && minutes <= 9) {
    minutes = "0" + minutes;
  }
  if (seconds >= 0 && seconds <= 9) {
    seconds = "0" + seconds;
  }

  return year + "-" + month + "-" + day + " " + hour + sign2 + minutes + sign2 + seconds;
}

后台代码

先创建模板文件

<html lang="zh-CN">

<head>
    <meta content="text/html; charset=utf-8" http-equiv="content-type">
    <meta name="referrer" content="never">
    <meta name="viewport"
          content="width=device-width, initial-scale=1,   minimum-scale=1,   maximum-scale=1,user-scalable=no">

    <style>
        html, body {
            padding: 0;
            margin: 0;
        }

        * {
            word-break:break-all;
        }

        #content {
            width: 92.2%;
            /*height: 100%;*/
            padding: 0;
            margin: 5px auto 0;
        }

        /* table 样式 */
        table {
            border-top: 1px solid #ccc;
            border-left: 1px solid #ccc;
        }

        table td,
        table th {
            border-bottom: 1px solid #ccc;
            border-right: 1px solid #ccc;
            padding: 3px 5px;
        }

        table th {
            border-bottom: 2px solid #ccc;
            text-align: center;
        }

        /* ul ol 样式 */
        ul, ol {
            margin: 10px 0 10px 20px;
        }

        /* video 设置*/
        video {
            width: 100%;
            height: auto;
        }
    </style>

    <title>${title}</title>
</head>
<body>
<div id="content">
    <#--   <h1 style="margin: 10px 0px 0px; padding: 0px; text-align: center; color: rgb(0, 0, 0); line-height: 30px; font-size: 21px; font-weight: normal; white-space: normal;">-->
    <#--       -->
    <#--   </h1>-->
    <#--   <p style="text-align: center;"><span style="text-align: center; color: rgb(102, 102, 102); font-family: Courier New, Courier, monospace; font-size: 12px; white-space: normal;">2022-07-22</span></p>-->

    <#-- 富文本中的内容     -->
    ${content}
</div>
<script>

    window.onload = function () {
        //视频:
        let videos = document.getElementsByTagName('video');
        videos = Array.from(videos);
        videos.forEach((video) => {
            video.setAttribute("controls", "controls");
            video.setAttribute("controlslist", "nodownload");
        });

        // let imgs = document.getElementsByTagName('img');
        // imgs = Array.from(imgs);
        // imgs.forEach((img) => {
            // console.log(img)
            // img.style.width = '100%';
            // img.style.maxWidth = '100%';
            // img.style.height = 'auto';
        // });

    }
    // document.getElementsByTagName()


</script>

</body>
</html>

这些配置是必要的,如果使用的是ruoyi那么请自行修改

# 项目相关配置
myWeb:
  # 名称
  name: myWeb
  # 版本
  version: 0.0.1
  # 版权年份
  copyrightYear: 2021
  # 实例演示开关
  demoEnabled: false
  # 文件路径 示例( Windows配置D:/myWeb/uploadPath,Linux配置 /home/myWeb/uploadPath)
  profile: ./uploadfile
#  profile: D:/home/file
  # 获取ip地址开关
  addressEnabled: false
  # 验证码类型 math 数组计算 char 字符验证
  captchaType: char
  # 共享盘映射地址,示例( Windows配置D:/myWeb/uploadPath,Linux配置 /home/myWeb/uploadPath)
#  sharedDisk: /HceShare/hceapp
  sharedDisk: D:/HceShare/hceapp
  # 上传的文件大小 140MB
  fileMaxSize: 146800640


# 静态资源对应的服务器域名或地址
# 生产地址
#serverPrefix: https://xxxxxxx:9969/RecordFile
# 测试环境地址
#serverPrefix: http://xxxxxxx:8043/ggpt
# 本地
serverPrefix: http://localhost:8043/ggpt

接下来最重要的地方,就是后台对富文本地址的处理,这个是控制器

    @Value("${serverPrefix}")
    public String serverPrefix;

    @RepeatSubmit(interval = 3500)
    public AjaxResult add(OpeNewsInfo opeNewsInfo) throws IOException, TemplateException, ParseException {


        LoginUser loginUser = getLoginUser();
        // 上传到共享盘,成功后会返回路径,调用的是otherAddressesUpload()
        String picaddr = FileUploadUtils.upload(myWeb.getSharedDiskImgPash(), myWeb.getSharedDisk(), opeNewsInfo.getPicNmFile());


        // 如果是本地页面才会生成页面
        if ("0".equals(opeNewsInfo.getPageType()) ) {
            // 获取内容
            String htmlAddress = FreemarkBeanUtil.getHtmlAddress(opeNewsInfo.getNewsTitle(), opeNewsInfo.getNewsContent(), loginUser);
            opeNewsInfo.setNewsLinkAddress(StringUtils.isNotEmpty(htmlAddress) ? serverPrefix + htmlAddress : "");
        }

插入数据库。。。。。
}

接下来必要的工具里类FileUploadUtils

package com.goldsign.common.utils.file;

import java.io.*;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.util.Map;

import cn.hutool.core.util.ByteUtil;
import cn.hutool.core.util.URLUtil;
import com.goldsign.common.utils.ServletUtils;
import com.goldsign.common.utils.VideoUtil;
import com.goldsign.common.utils.ip.IpUtils;
import org.apache.commons.compress.utils.IOUtils;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.io.FilenameUtils;
import org.apache.http.entity.ContentType;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import com.goldsign.common.config.GoldSignConfig;
import com.goldsign.common.constant.Constants;
import com.goldsign.common.exception.file.FileNameLengthLimitExceededException;
import com.goldsign.common.exception.file.FileSizeLimitExceededException;
import com.goldsign.common.exception.file.InvalidExtensionException;
import com.goldsign.common.utils.DateUtils;
import com.goldsign.common.utils.StringUtils;
import com.goldsign.common.utils.uuid.IdUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;

/**
 * 文件上传工具类
 *
 * @author ruoyi
 */
@Component
public class FileUploadUtils {

    protected static final Logger log = LoggerFactory.getLogger(FileUploadUtils.class);

    @Autowired
    static IpUtils ipUtils;

    @Value("${serverPrefix}")
    public String serverPrefix;

    public static String serve_prefix;

    //利用@PostConstruct将yml中配置的值赋给本地的变量
    @PostConstruct
    public void getEnvironment() {
        this.serve_prefix = this.serverPrefix;
    }

    /**
     * 默认的文件名最大长度 100
     */
    public static final int DEFAULT_FILE_NAME_LENGTH = 350;

    /**
     * 默认上传的地址
     */
    private static String defaultBaseDir = GoldSignConfig.getProfile();

    public static void setDefaultBaseDir(String defaultBaseDir) {
        FileUploadUtils.defaultBaseDir = defaultBaseDir;
    }

    public static String getDefaultBaseDir() {
        return defaultBaseDir;
    }

    /**
     * 以默认配置进行文件上传
     *
     * @param file 上传的文件
     * @return 文件名称
     * @throws Exception
     */
    public static final String upload(MultipartFile file) throws IOException {
        try {
            return upload(getDefaultBaseDir(), null, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);
        } catch (Exception e) {
            throw new IOException(e.getMessage(), e);
        }
    }

    /**
     * 根据文件路径上传
     *
     * @param baseDir         相对应用的基目录
     * @param fileHttpMapping 文件所存在的映射根目录,该目录被资源拦截器映射成了本服务的的静态资源
     * @param file            上传的文件
     * @return 文件名称
     * @throws IOException
     */
    public static final String upload(String baseDir, String fileHttpMapping, MultipartFile file) throws IOException {
        try {
            return upload(baseDir, fileHttpMapping, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);
        } catch (Exception e) {
            throw new IOException(e.getMessage(), e);
        }
    }


    /**
     * 文件上传
     *
     * @param baseDir          相对应用的基目录
     * @param fileHttpMapping  文件所存在的映射根目录,该目录被资源拦截器映射成了本服务的的静态资源
     * @param file             上传的文件
     * @param allowedExtension 上传文件类型
     * @return 返回上传成功的文件名
     * @throws FileSizeLimitExceededException       如果超出最大大小
     * @throws FileNameLengthLimitExceededException 文件名太长
     * @throws IOException                          比如读写文件出错时
     * @throws InvalidExtensionException            文件校验异常
     */
    public static final String upload(String baseDir, String fileHttpMapping, MultipartFile file, String[] allowedExtension) throws Exception {

        int fileNamelength = file.getOriginalFilename().length();
        if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH) {
            throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH);
        }

        assertAllowed(file, allowedExtension);
        String fileName = extractFilename(file);

        File desc = getAbsoluteFile(baseDir, fileName);
        file.transferTo(desc);
        String pathFileName = getPathFileName(baseDir, fileHttpMapping, fileName);
        return pathFileName;
    }

    /**
     * 编码文件名
     */
    public static final String extractFilename(MultipartFile file) {
        String fileName = file.getOriginalFilename();
        String extension = getExtension(file);
        fileName = DateUtils.datePath() + "/" + IdUtils.fastUUID() + "." + extension;
        return fileName;
    }

    public static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException {
        File desc = new File(uploadDir + File.separator + fileName);

        if (!desc.exists()) {
            if (!desc.getParentFile().exists()) {
                desc.getParentFile().mkdirs();
            }
        }
        return desc;
    }

    public static final String getPathFileName(String uploadDir, String fileHttpMapping, String fileName) throws IOException {
        if (fileHttpMapping == null) {
            fileHttpMapping = GoldSignConfig.getProfile();
        }
        String pathFileName;
        int dirLastIndex = fileHttpMapping.length() + 1;
        String currentDir = StringUtils.substring(uploadDir, dirLastIndex);
        // 如果是本服務對應的文件夾,那麽就加上指定前綴,可以让该请求访问本服务时,映射到指定的静态资源上
        if (fileHttpMapping.equals(GoldSignConfig.getProfile())) {
            // Constants.RESOURCE_PREFIX 是本服务默认的开头前缀
            pathFileName = Constants.RESOURCE_PREFIX + "/" + currentDir + "/" + fileName;
        } else {
            // 这个就不用加前缀, 因为其他服务(hce后管)也要访问,所以我们文件路径的格式不能和框架指定的格式保持一致,要跟hce后管的文件系统保持一致,而且上传的时候我们也指定了前缀,如果要加新的文件类型,则在配置文件中增加配置,同时在ResourcesConfig中增加对该目录的映射处理
            pathFileName = "/" + currentDir + "/" + fileName;
        }
        return pathFileName;
    }

    /**
     * 文件大小校验
     *
     * @param file 上传的文件
     * @return
     * @throws FileSizeLimitExceededException 如果超出最大大小
     * @throws InvalidExtensionException
     */
    public static final void assertAllowed(MultipartFile file, String[] allowedExtension) throws FileSizeLimitExceededException, InvalidExtensionException {
        long size = file.getSize();

        long fileMaxSize = GoldSignConfig.getFileMaxSize();
        if (fileMaxSize != -1 && size > fileMaxSize) {
            throw new FileSizeLimitExceededException(fileMaxSize / 1024 / 1024);
        }

        String fileName = file.getOriginalFilename();
        String extension = getExtension(file);
        if (allowedExtension != null && !isAllowedExtension(extension, allowedExtension)) {
            if (allowedExtension == MimeTypeUtils.IMAGE_EXTENSION) {
                throw new InvalidExtensionException.InvalidImageExtensionException(allowedExtension, extension,
                        fileName);
            } else if (allowedExtension == MimeTypeUtils.FLASH_EXTENSION) {
                throw new InvalidExtensionException.InvalidFlashExtensionException(allowedExtension, extension,
                        fileName);
            } else if (allowedExtension == MimeTypeUtils.MEDIA_EXTENSION) {
                throw new InvalidExtensionException.InvalidMediaExtensionException(allowedExtension, extension,
                        fileName);
            } else if (allowedExtension == MimeTypeUtils.VIDEO_EXTENSION) {
                throw new InvalidExtensionException.InvalidVideoExtensionException(allowedExtension, extension,
                        fileName);
            } else {
                throw new InvalidExtensionException(allowedExtension, extension, fileName);
            }
        }

    }

    /**
     * 判断MIME类型是否是允许的MIME类型
     *
     * @param extension
     * @param allowedExtension
     * @return
     */
    public static final boolean isAllowedExtension(String extension, String[] allowedExtension) {
        for (String str : allowedExtension) {
            if (str.equalsIgnoreCase(extension)) {
                return true;
            }
        }
        return false;
    }

    // 根据网页内容生成h5文件
    public static String getH5Path(String h5Path, String content) throws IOException {
        InputStream inputStream = null;
        try {

            inputStream = new ByteArrayInputStream(content.getBytes());
            MultipartFile vFile = new MockMultipartFile("xx.html", "xx.html", ContentType.TEXT_HTML.toString(), inputStream);

            // 保存新闻,这里获取的是h5
            h5Path = upload(GoldSignConfig.getSharedDiskH5Pash(), GoldSignConfig.getSharedDisk(), vFile);
        } catch (IOException e) {
            e.printStackTrace();
            log.error("网页生成上传失败,网页URL:{},异常:{}", h5Path, e.getMessage());
        } finally {
            if (inputStream != null) {
                inputStream.close();
            }
        }
        return h5Path;
    }

    /**
     * 获取文件名的后缀
     *
     * @param file 表单文件
     * @return 后缀名
     */
    public static final String getExtension(MultipartFile file) {
        String extension = FilenameUtils.getExtension(file.getOriginalFilename());
        if (StringUtils.isEmpty(extension)) {
            extension = MimeTypeUtils.getExtension(file.getContentType());
        }
        return extension;
    }

    /**
     * 将相对服务的相对路径,修改为相对为本文件的路径,避免服务地址修改的时候,或者服务名修改的时候产生不必要的维护
     *
     * @param els
     */
    public static void extracted(Elements els) throws IOException {
        String src;
        for (Element el : els) {


            if ("video".equals(el.tag().getName())) {
                Elements source = el.select("source[src]");
                src = source.attr("src");
                if (StringUtils.isNotBlank(src)) {
                    // 第一步,判断是否是绝对路径
                    if (!isAbsolutePath(src)) {
                        // 相对路径设置
                        el.attr("src", getHtmlTagRelativeUrl(src));
                    }

                    // 第二步,先不修改src的地址为相对地址,先获取视频封面字节数据
                    byte[] bytesImg = VideoUtil.getScreenshot(src);
                    if (bytesImg != null) {
                        MultipartFile vFile = null;
                        InputStream inputStream = null;
                        try {
                            // 构造inputStream
                            inputStream = new ByteArrayInputStream(bytesImg);
                            // 将inputStream转成MultipartFile
                            vFile = new MockMultipartFile("xx.jpeg", "xx.jpeg", ContentType.IMAGE_JPEG.toString(), inputStream);
                            // 上传封面。获取上传后的地址
                            String h5Path = upload(GoldSignConfig.getSharedDiskCVideoCoverPath(), GoldSignConfig.getSharedDisk(), vFile);
                            el.attr("poster", getHtmlTagRelativeUrl(h5Path));
                        } catch (IOException e) {
                            e.printStackTrace();
                            log.error("视频封面转换失败,视频URL:{},异常:{}", src, e.getMessage());
                        } finally {
                            if (inputStream != null) {
                                inputStream.close();
                            }
                        }
                    }
                }
            } else {
                src = el.attr("src");
                el.attr("src", getHtmlTagRelativeUrl(src));
                String style = el.attr("style");
                el.attr("style", "max-width: 100%;height: auto");
            }
        }
    }

    /**
     * 为标签设置图片,修改相对路径
     *
     * @param src
     */
    private static String getHtmlTagRelativeUrl(String src) {
        // 判断如果有 配置文件中的serverPrefix地址,那么就替换成空字符串,这样在生成的文件中保存的就是相对地址了,相对地址不依赖域名,更灵活
        src = src.replace(serve_prefix, "");
        // 如果是以userfile开头的就替换
        if (src.startsWith("/userfiles/ggpt/")) {
            // 这里替换成相对路径,避免不必要的拼接数据,造成元数据污染
            return src.replace("/userfiles/ggpt/", "../../../../");
        }
        return src;
    }

    /**
     * 将字符串通过outputStream输入到file中
     * 这个方法有问题,会在本地生成文件,所以放弃使用了
     *
     * @param title
     * @param htmlText
     * @return
     * @throws IOException
     */
    public static CommonsMultipartFile getCommonsMultipartFile(String title, String htmlText, File file) throws IOException {
        // file为空就使用htmlcontent,否则就使用传递进来的file
        if (file == null) {
            file = new File(title + ".html");
            OutputStream fos = new FileOutputStream(file);
            fos.write(htmlText.getBytes(StandardCharsets.UTF_8));
            try {
                fos.flush();
                fos.close();
            } catch (IOException e) {

            }
        }

        DiskFileItem fileItem = (DiskFileItem) new DiskFileItemFactory().createItem("file", MediaType.ALL_VALUE, true, file.getName());


        try (InputStream input = new FileInputStream(file); OutputStream os = fileItem.getOutputStream()) {
            IOUtils.copy(input, os);
        } catch (Exception e) {
            throw new IllegalArgumentException("Invalid file: " + e, e);
        }

        CommonsMultipartFile multipartFile = new CommonsMultipartFile(fileItem);
        return multipartFile;
    }

    /**
     * 判断是否绝对路径
     * 当路径以 / 开头则为相对路径,否则视为绝对路径
     *
     * @param uploadDir
     * @return
     */
    private static boolean isAbsolutePath(String uploadDir) {
        if (uploadDir.startsWith("/")) {
            return false;
        }
        return true;
    }

    /**
     * 获取本机地址
     *
     * @return
     */
    public static String getUrl() {
        return getDomain(ServletUtils.getRequest());
    }

    public static String getDomain(HttpServletRequest request) {
        StringBuffer url = request.getRequestURL();
        String contextPath = request.getServletContext().getContextPath();
        return url.delete(url.length() - request.getRequestURI().length(), url.length()).append(contextPath).toString();
    }

}

视频封面截取工具VideoUtil

package com.goldsign.common.utils;

import cn.hutool.core.img.ImgUtil;
import com.goldsign.common.exception.ServiceException;
import com.goldsign.common.utils.ip.IpUtils;
import com.goldsign.common.utils.uuid.IdUtils;
//import org.bytedeco.javacpp.opencv_core;
//import org.bytedeco.javacv.FFmpegFrameGrabber;
//import org.bytedeco.javacv.Frame;
//import org.bytedeco.javacv.Java2DFrameConverter;

//import java.awt.*;
//import java.awt.image.BufferedImage;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
//import java.io.File;
//
import org.bytedeco.javacpp.opencv_core;
import org.bytedeco.javacv.*;
import org.bytedeco.javacv.Frame;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.imageio.ImageIO;

/**
 * @author:yuchen
 * @createTime:2022/7/11 16:07
 */
@Component
public class VideoUtil {

    protected static final Logger log = LoggerFactory.getLogger(VideoUtil.class);

    public static void main(String[] args) {


//        byte[] screenshot = getScreenshot("C:\\Users\\86181\\Downloads\\下载 (1).mp4");


//        System.out.println(file.getName());

//        getVideoPic();
    }

    @Autowired
    public IpUtils ipUtils;

    @Autowired
    public static IpUtils _ipUtils;

    @Value("${serverPrefix}")
    public String serverPrefix;

    public static String serve_prefix;

    //利用@PostConstruct将yml中配置的值赋给本地的变量
    @PostConstruct
    public void getEnvironment(){
        this.serve_prefix = this.serverPrefix;
        this._ipUtils = this.ipUtils;
    }

//    public static String getVideoPic() {
//        String url = "https://xxx/xxxx.mp4";
//        String value = "1111123";
//        String dir = value +"/";
//        String fileName = FileUtil.getName(url);// 100.mp4
//        String targetFileName = "thumb_"+fileName.substring(0, fileName.lastIndexOf("."))+".jpg";
//        File filePath = new File(PATH+dir);
//        if (!filePath.exists()) {
//            boolean mkdirs = filePath.mkdirs();
//            if(mkdirs){
//                log.info("文件夹创建成功:{}",filePath.getAbsolutePath());
//            }
//        }
//        String outPath = PATH+dir+targetFileName;
//        File outFile = getScreenshot(url, outPath);
//        if(outFile != null){
//            String fileName1 = AwsFileUtil.uploadS3Us(outFile, imei, targetFileName);
//            System.out.println(fileName1);
//            boolean delete = outFile.delete();
//            if(delete){
//                log.info("删除本地临时文件成功");
//            }
//            return fileName1;
//        }
//        return "";
//    }

    /**
     * 获取视频封面图
     *
     * @param filePath 视频地址
     * @return map
     */
//    public static byte[] getScreenshot(String filePath) {
//        log.info("截取视频截图开始:Video={}", filePath);
//        filePath = filePath.replaceAll("\\\\", "/");
//        File file = null;
//        FFmpegFrameGrabber grabber = null;
//        try {
//            grabber = FFmpegFrameGrabber.createDefault(filePath);
//            grabber.setOption("stimeout", "2000000");
//            grabber.start();
//            //设置视频截取帧(建议从5帧开始,防止全是黑屏)
//            Frame frame = null;
//            for (int j = 0; j < 5; j++) {
//                frame = grabber.grabImage();
//            }
//            //视频旋转度
//            String rotate = grabber.getVideoMetadata("rotate");
//            Java2DFrameConverter converter = new Java2DFrameConverter();
//            //绘制图片
//            BufferedImage image = converter.getBufferedImage(frame);
//            if (rotate != null) {
//                // 旋转图片
//                image = rotate(image, Integer.parseInt(rotate));
//            }
//            //创建文件
            file = new File(IdUtils.randomUUID() + ".jpg");
            ImgUtil.write(image, file);
//
//            ByteArrayOutputStream out = new ByteArrayOutputStream();
//            boolean flag = ImageIO.write(image, "gif", out);
//
//            byte[] b = out.toByteArray();
//            out.write(b);
//            log.info("截取视频截图成功");
//            return b;
//        } catch (Exception e) {
//            throw new ServiceException("获取视频封面图,Error,请检查视频链接是否正常");
//        } finally {
//            if (grabber != null) {
//                try {
//                    grabber.stop();
//                } catch (Exception ignored) {
//                }
//            }
//        }
//    }



    public static byte[] getScreenshot(String filePath) {

        // 说明是外部资源,需要拼接上https
        if (filePath.startsWith("//") && !filePath.startsWith("/userfiles/ggpt")){
            filePath = "https:" + filePath;
        }

        // 有些连文件地址不太正常,且没有后缀,不要紧; 文档资料参考链接:【https://www.codenong.com/7273573/】

        // 如果发现是以yml配置开头的url路径,那么就替换成localhost路径
        filePath = filePath.replaceFirst(serve_prefix,_ipUtils.getAccessPath());
        byte[] bytes = null;
        FFmpegFrameGrabber ff = null;

        try {

            ff = FFmpegFrameGrabber.createDefault(filePath);
            ff.start();
            String rotate = ff.getVideoMetadata("rotate");
            Frame f;
            int i = 0;
            while (i < 6) {
                f = ff.grabImage();
                opencv_core.IplImage src = null;
                if (null != rotate && rotate.length() > 1) {
                    OpenCVFrameConverter.ToIplImage converter = new OpenCVFrameConverter.ToIplImage();
                    src = converter.convert(f);
                    f = converter.convert(rotate(src, Integer.valueOf(rotate)));
                }
                i++;
                if (i == 6) {
                    bytes = doExecuteFrame(f);
                }
            }

            ff.stop();

        } catch (FrameGrabber.Exception e) {
            log.error("视频截取失败");
//            throw new ServiceException("获取视频封面图,Error,请检查视频链接是否正常");
        } finally {
            if (ff != null) {
                try {
                    ff.close();
                } catch (Exception e) {
                }
            }
        }
        return bytes;
    }

    /*
     * 旋转角度的
     */
    public static opencv_core.IplImage rotate(opencv_core.IplImage src, int angle) {
        opencv_core.IplImage img = opencv_core.IplImage.create(src.height(), src.width(), src.depth(), src.nChannels());
        opencv_core.cvTranspose(src, img);
        opencv_core.cvFlip(img, img, angle);
        return img;
    }

    public static byte[] doExecuteFrame(Frame f) {

        if (null == f || null == f.image) {
            return new byte[0];
        }
        Java2DFrameConverter converter = new Java2DFrameConverter();
        String imageMat = "jpg";
        BufferedImage bi = converter.getBufferedImage(f);
        System.out.println("width:" + bi.getWidth());
        System.out.println("height:" + bi.getHeight());

        ByteArrayOutputStream out = new ByteArrayOutputStream();
        try {
            boolean flag = ImageIO.write(bi, "jpg", out);
            byte[] b = out.toByteArray();
            log.info("截取视频截图成功");
            return b;
        } catch (IOException e) {
            log.error("封面截取失败");
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {

                }
            }
        }
        return null;
    }


    /**
     * @param src   ""
     * @param angel 视频旋转度
     * @return BufferedImage
     * @Description 根据视频旋转度来调整图片
     */
    private static BufferedImage rotate(BufferedImage src, int angel) {
        int src_width = src.getWidth(null);
        int src_height = src.getHeight(null);
        int type = src.getColorModel().getTransparency();
        Rectangle rect_des = calcRotatedSize(new Rectangle(new Dimension(src_width, src_height)), angel);
        BufferedImage bi = new BufferedImage(rect_des.width, rect_des.height, type);
        Graphics2D g2 = bi.createGraphics();
        g2.translate((rect_des.width - src_width) / 2, (rect_des.height - src_height) / 2);
        g2.rotate(Math.toRadians(angel), src_width / 2, src_height / 2);
        g2.drawImage(src, 0, 0, null);
        g2.dispose();
        return bi;
    }


    /**
     * @param src   ""
     * @param angel ""
     * @return Rectangle
     * @Description: 计算图片旋转大小
     */
    private static Rectangle calcRotatedSize(Rectangle src, int angel) {
        if (angel >= 90) {
            if (angel / 90 % 2 == 1) {
                int temp = src.height;
                src.height = src.width;
                src.width = temp;
            }
            angel = angel % 90;
        }
        double r = Math.sqrt(src.height * src.height + src.width * src.width) / 2;
        double len = 2 * Math.sin(Math.toRadians(angel) / 2) * r;
        double angel_alpha = (Math.PI - Math.toRadians(angel)) / 2;
        double angel_dalta_width = Math.atan((double) src.height / src.width);
        double angel_dalta_height = Math.atan((double) src.width / src.height);
        int len_dalta_width = (int) (len * Math.cos(Math.PI - angel_alpha - angel_dalta_width));
        int len_dalta_height = (int) (len * Math.cos(Math.PI - angel_alpha - angel_dalta_height));
        int des_width = src.width + len_dalta_width * 2;
        int des_height = src.height + len_dalta_height * 2;
        return new java.awt.Rectangle(new Dimension(des_width, des_height));
    }

}

对yml中的配置文件进行装配myWebnConfig

package com.goldsign.common.config;

import org.apache.commons.lang3.time.DateUtils;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.io.File;
import java.util.Date;

/**
 * 读取项目相关配置
 *
 * @author ruoyi
 */
@Component
@ConfigurationProperties(prefix = "myWeb")
public class myWebSignConfig {
    /**GoldSignConfig
     * 项目名称
     */
    private String name;

    /**
     * 版本
     */
    private String version;

    /**
     * 版权年份
     */
    private String copyrightYear;

    /**
     * 实例演示开关
     */
    private boolean demoEnabled;

    /**
     * 上传最大文件大小配置
     */
    private static long fileMaxSize;

    /**
     * 上传路径
     */
    private static String profile;

    /* 共享盘地址*/
    private static String sharedDisk;

    /**
     * 获取地址开关
     */
    private static boolean addressEnabled;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getVersion() {
        return version;
    }

    public void setVersion(String version) {
        this.version = version;
    }

    public String getCopyrightYear() {
        return copyrightYear;
    }

    public void setCopyrightYear(String copyrightYear) {
        this.copyrightYear = copyrightYear;
    }

    public boolean isDemoEnabled() {
        return demoEnabled;
    }

    public void setDemoEnabled(boolean demoEnabled) {
        this.demoEnabled = demoEnabled;
    }

    public static String getProfile() {
        return profile;
    }

    public void setProfile(String profile) {
        GoldSignConfig.profile = profile;
    }

    public static boolean isAddressEnabled() {
        return addressEnabled;
    }

    public void setAddressEnabled(boolean addressEnabled) {
        GoldSignConfig.addressEnabled = addressEnabled;
    }

    public static String getSharedDisk() {
        return sharedDisk;
    }

    public void setSharedDisk(String sharedDisk) {
        GoldSignConfig.sharedDisk = sharedDisk;
    }

    public static long getFileMaxSize() {
        return fileMaxSize;
    }

    public void setFileMaxSize(long fileMaxSize) {
        GoldSignConfig.fileMaxSize = fileMaxSize;
    }

    /**
     * 获取导入上传路径
     */
    public static String getImportPath() {
        return getProfile() + "/import";
    }


    /**
     * 获取头像上传路径
     */
    public static String getAvatarPath() {
        return getProfile() + "/avatar";
    }

    /**
     * 获取下载路径
     */
    public static String getDownloadPath() {
        return getProfile() + "/download/";
    }

    /**
     * 获取上传路径
     */
    public static String getUploadPath() {
        return getProfile() + "/upload";
    }


    /**
     * 获取共享盘图片上传路径
     *
     * @return
     */
    public static String getSharedDiskImgPash() {
        // 如果上传的目录不1位则补0
        String path = getSharedDisk() + "/userfiles/ggpt/image";
        File file = new File(path);
        if (file.exists()) {
            file.mkdirs();
        }
        return path;
    }

    /**
     * 获取共享盘【视频文件】上传路径
     *
     * @return
     */
    public static String getSharedDiskVideoPash() {
        // 如果上传的目录不1位则补0
        String path = getSharedDisk() + "/userfiles/ggpt/video";
        File file = new File(path);
        if (file.exists()) {
            file.mkdirs();
        }
        return path;
    }


    /**
     * 获取共享盘网页上传路径
     *
     * @return
     */
    public static String getSharedDiskH5Pash() {
        // 如果上传的目录不1位则补0
        String path = getSharedDisk() + "/userfiles/ggpt/h5";
        File file = new File(path);
        if (file.exists()) {
            file.mkdirs();
        }
        return path;
    }

    /**
     * 获取共享盘图片上传路径
     *
     * @return
     */
    public static String getSharedDiskCVideoCoverPath() {
        // 如果上传的目录不1位则补0
        String path = getSharedDisk() + "/userfiles/ggpt/videoCover";
        File file = new File(path);
        if (file.exists()) {
            file.mkdirs();
        }
        return path;
    }


}

必须依赖,如果是ruoyi框架请加载common模块下

        <!-- 解析文档 -->
        <dependency>
            <groupId>org.jsoup</groupId>
            <artifactId>jsoup</artifactId>
            <version>1.8.3</version>
        </dependency>
        视频处理
        <dependency>
            <groupId>org.bytedeco</groupId>
            <artifactId>javacv-platform</artifactId>
            <version>1.3.1</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
        </dependency>

        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.7.13</version>
        </dependency>


最重要的环节来了,springmvc添加 addResourceHandlers

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        /** 本地文件上传路径 */
        // 后管服务自带的目录
        registry.addResourceHandler(Constants.RESOURCE_PREFIX + "/**")
                // 映射到指定的目錄
                .addResourceLocations("file:" + GoldSignConfig.getProfile() + "/");

        // 这里是hce后管的文件目录,如果是userfiles路径,那么映射到D:/HceShare/hceapp + “/userfiles/” 目录下面
        registry.addResourceHandler("/userfiles" + "/**")
                // 映射到指定的目錄
                .addResourceLocations("file:" + GoldSignConfig.getSharedDisk() + "/userfiles/");

        /** swagger配置 */
        registry.addResourceHandler("/swagger-ui/**")
                .addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/");
    }

最后ruoyi的权限框架不要拦截我们的目录文件

类OpeAdPicInfo

package com.goldsign.domain;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.goldsign.common.annotation.Excel;
import lombok.experimental.FieldDefaults;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.springframework.web.multipart.MultipartFile;

import java.util.Date;

/**
 * 广告轮播图对象 OPE_AD_PIC_INFO
 * 
 * @author goldsign
 * @date 2022-07-08
 */
@KeySequence(value = "SEQ_OPE_AD_PIC_INFO", clazz = String.class)
public class OpeAdPicInfo extends Model<OpeAdPicInfo> {

    private static final long serialVersionUID = 1L;

    /** 上传的图片文件 */
    private MultipartFile picNmFile;

    /** $column.columnComment */
    @TableId(value = "id", type = IdType.INPUT)
    private String id;

    /** 图片名称 */
    @Excel(name = "图片名称")
    private String picNm;

    /** 图片地址 */
    @Excel(name = "图片地址")
    private String picAddr;

    /** 图片描叙 */
    @Excel(name = "图片描叙")
    private String picDesc;

    /** 图片是否显示 */
    @Excel(name = "图片是否显示")
    private String picShow;

    /** 创建人 */
    @Excel(name = "创建人")
    private String creater;

    /** 创建时间 */
    @Excel(name = "创建时间")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date createDt;

    /** 最新修改人 */
    @Excel(name = "最新修改人")
    private String modifier;

    /** 最新修改时间 */
    @Excel(name = "最新修改时间")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date modifyDt;

    /** 备注 */
    @Excel(name = "备注")
    private String remarks;

    /** 删除标记 */
    private String deleteFlag;

    /** 图片超链接 */
    @Excel(name = "图片超链接")
    private String picHyperlink;

    /** 广告类型 */
    @Excel(name = "广告类型")
    private String adType;

    /** 广告类型 */
    @Excel(name = "广告类型")
    private String linkType;

    /** 倒计时(秒) */
    @Excel(name = "倒计时", readConverterExp = "秒")
    private Integer countdown;

    /** $column.columnComment */
    @Excel(name = "倒计时", readConverterExp = "$column.readConverterExp()")
    private String savepic;

    @Excel(name = "发布时间")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date releaseTime;

    @Excel(name = "锁定时间")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date lockTime;

    /** 富文本 */
    private String richText;

    // 网页类型,0本地页面,1第三方页面
    private String pageType;

    public String getPageType() {
        return pageType;
    }

    public void setPageType(String pageType) {
        this.pageType = pageType;
    }

    public Date getReleaseTime() {
        return releaseTime;
    }

    public void setReleaseTime(Date releaseTime) {
        this.releaseTime = releaseTime;
    }

    public Date getLockTime() {
        return lockTime;
    }

    public void setLockTime(Date lockTime) {
        this.lockTime = lockTime;
    }

    public String getRichText() {
        return richText;
    }

    public void setRichText(String richText) {
        this.richText = richText;
    }

    public void setId(String id)
    {
        this.id = id;
    }

    public String getId()
    {
        return id;
    }
    public void setPicNm(String picNm)
    {
        this.picNm = picNm;
    }

    public String getPicNm() 
    {
        return picNm;
    }
    public void setPicAddr(String picAddr) 
    {
        this.picAddr = picAddr;
    }

    public String getPicAddr() 
    {
        return picAddr;
    }
    public void setPicDesc(String picDesc) 
    {
        this.picDesc = picDesc;
    }

    public String getPicDesc() 
    {
        return picDesc;
    }
    public void setPicShow(String picShow) 
    {
        this.picShow = picShow;
    }

    public String getPicShow() 
    {
        return picShow;
    }
    public void setCreater(String creater) 
    {
        this.creater = creater;
    }

    public String getCreater() {
        return creater;
    }

    public Date getCreateDt() {
        return createDt;
    }

    public void setCreateDt(Date createDt) {
        this.createDt = createDt;
    }

    public String getModifier() {
        return modifier;
    }

    public void setModifier(String modifier) {
        this.modifier = modifier;
    }

    public Date getModifyDt() {
        return modifyDt;
    }

    public void setModifyDt(Date modifyDt) {
        this.modifyDt = modifyDt;
    }

    public void setRemarks(String remarks) {
        this.remarks = remarks;
    }

    public String getRemarks()
    {
        return remarks;
    }
    public void setDeleteFlag(String deleteFlag) 
    {
        this.deleteFlag = deleteFlag;
    }

    public String getDeleteFlag() 
    {
        return deleteFlag;
    }
    public void setPicHyperlink(String picHyperlink) 
    {
        this.picHyperlink = picHyperlink;
    }

    public String getPicHyperlink() 
    {
        return picHyperlink;
    }
    public void setAdType(String adType) 
    {
        this.adType = adType;
    }

    public String getAdType() 
    {
        return adType;
    }
    public void setLinkType(String linkType) 
    {
        this.linkType = linkType;
    }

    public String getLinkType() 
    {
        return linkType;
    }
    public void setCountdown(Integer countdown) 
    {
        this.countdown = countdown;
    }

    public Integer getCountdown() 
    {
        return countdown;
    }
    public void setSavepic(String savepic) 
    {
        this.savepic = savepic;
    }

    public String getSavepic() 
    {
        return savepic;
    }

    public MultipartFile getPicNmFile() {
        return picNmFile;
    }

    public void setPicNmFile(MultipartFile picNmFile) {
        this.picNmFile = picNmFile;
    }

    @Override
    public String toString() {
        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
            .append("id", getId())
            .append("picNm", getPicNm())
            .append("picAddr", getPicAddr())
            .append("picDesc", getPicDesc())
            .append("picShow", getPicShow())
            .append("creater", getCreater())
            .append("createDt", getCreateDt())
            .append("modifier", getModifier())
            .append("modifyDt", getModifyDt())
            .append("remarks", getRemarks())
            .append("deleteFlag", getDeleteFlag())
            .append("picHyperlink", getPicHyperlink())
            .append("adType", getAdType())
            .append("linkType", getLinkType())
            .append("countdown", getCountdown())
            .append("savepic", getSavepic())
            .toString();
    }
}

 有些包名和类型没处理干净,如果有人使用请注意修改

在sys_menu中有路由参数配置,请参考ruoyi官网配置,vue组件中有用到

需要用到ipUtils这个在若依里面有,就是用来获取当前服务的地址和端口号+服务名的

最后还需要修改若依框架的上传代码中文件路径的参数设置

Logo

快速构建 Web 应用程序

更多推荐