基于RuoYi-Flowable-Plus的ruoyi-nbcio项目的formdesigner文件上传与回显处理

news2024/11/24 6:27:27

   更多ruoyi-nbcio功能请看演示系统

   gitee源代码地址

   前后端代码: https://gitee.com/nbacheng/ruoyi-nbcio

     

        本节说明ruoyi-nbcio项目的formdesigner文件上传与回显处理,不过目前还只实现oss的formdesigner的文件上传与回显功能。

     1、前端方面

      formdesigner的upload.js组件修改如下:

/**
 * 上传组件
 */
export let upload = {
  id:'',
  _id:'',
  compType: 'upload',
  ele: 'el-upload',
  //控件名称(左侧显示)
  compName:'附件',
  //图标
  compIcon:'att',
  //展示表单的模式
  viewType:'component',

  // 是否可配置
  //暂时默认为true,无法更改,后期考虑某些时候无法配置
  config: true,
  // 控件左侧label内容
  showLabel:true,
  label: '附件上传',
  labelWidth: '80',
  //栅格间隔
  gutter:15,
  //默认栅格
  span:24,
  // 是否必填
  required: false,
  //上传地址
  action:'http://122.227.135.243:9060/common/upload',
  //多选上传
  multiple:false,
  name:'file',
  //显示上传文件列表
  'show-file-list':true,
  //文件列表类型
  'list-type':'text',
  value:'',
  width:100,
  //按钮文字
  buttonText:'请上传附件',
  //是否显示描述
  showTip:false,
  //描述内容
  tips:'点击按钮上传附件',
  //允许文件类型
  accept:'.pdf, .doc, .docx, .xls, .xlsx, .gif, .png, .jpeg',
  //文件大小MB
  fileSize:10,
  headers:{"Authorization":"Bearer " + "token"},

     原先detail.vue修改如下:

    

<template>
  <div class="app-container">
    <el-tabs tab-position="top" v-model="activeName" :value="processed === true ? 'approval' : 'form'" @tab-click="changeTab">

      <el-tab-pane label="任务办理" name="approval" v-if="processed === true">
        <el-card class="box-card" shadow="hover" v-if="taskFormOpen">
          <div slot="header" class="clearfix">
            <span>填写表单</span>
          </div>
          <el-col :span="20" :offset="2">
            <parser :form-conf="taskFormData" ref="taskFormParser"/>
          </el-col>
        </el-card>
        <el-card class="box-card" shadow="hover">
          <div slot="header" class="clearfix">
            <span>审批流程</span>
          </div>
          <el-row>
            <el-col :span="20" :offset="2">
              <el-form ref="taskForm" :model="taskForm" :rules="rules" label-width="120px">
                <el-form-item label="审批意见" prop="comment">
                  <el-input type="textarea" :rows="5" v-model="taskForm.comment" placeholder="请输入 审批意见" />
                </el-form-item>
                <el-form-item label="抄送人" prop="copyUserIds">
                  <el-tag
                    :key="index"
                    v-for="(item, index) in copyUser"
                    closable
                    :disable-transitions="false"
                    @close="handleClose('copy', item)">
                    {{ item.nickName }}
                  </el-tag>
                  <el-button class="button-new-tag" type="primary" icon="el-icon-plus" size="mini" circle @click="onSelectCopyUsers" />
                </el-form-item>
                <el-form-item label="指定审批人" prop="copyUserIds">
                  <el-tag
                    :key="index"
                    v-for="(item, index) in nextUser"
                    closable
                    :disable-transitions="false"
                    @close="handleClose('next', item)">
                    {{ item.nickName }}
                  </el-tag>
                  <el-button class="button-new-tag" type="primary" icon="el-icon-plus" size="mini" circle @click="onSelectNextUsers" />
                </el-form-item>
              </el-form>
            </el-col>
          </el-row>
          <el-row :gutter="10" type="flex" justify="center" >
            <el-col :span="1.5">
              <el-button icon="el-icon-circle-check" type="success" @click="handleComplete">通过</el-button>
            </el-col>
            <el-col :span="1.5">
              <el-button icon="el-icon-chat-line-square" type="primary" @click="handleDelegate">委派</el-button>
            </el-col>
            <el-col :span="1.5">
              <el-button icon="el-icon-thumb" type="success" @click="handleTransfer">转办</el-button>
            </el-col>
            <el-col :span="1.5">
              <el-button icon="el-icon-refresh-left" type="warning" @click="handleReturn">退回</el-button>
            </el-col>
            <el-col :span="1.5">
              <el-button icon="el-icon-circle-close" type="danger" @click="handleReject">拒绝</el-button>
            </el-col>
          </el-row>
        </el-card>
      </el-tab-pane>

      <el-tab-pane label="表单信息" name="form">
        <div v-if="formOpen">
          <el-card class="box-card" shadow="never" v-for="(formInfo, index) in formViewData" :key="index">
            <!--<div slot="header" class="clearfix">
              <span>{{ formInfo.title }}</span>
            </div>-->
            <!--流程处理表单模块-->
            <el-col :span="20" :offset="2">
              <form-viewer ref="formViewer" v-model="formVal[index]" :buildData="formInfo" />
            </el-col>
          </el-card>
        </div>
        <div style="margin-left:10%;margin-bottom: 30px">
           <!--对上传文件进行显示处理,临时方案 add by nbacheng 2022-07-27 -->
           <el-upload action="#" :on-preview="handleFilePreview" :file-list="fileList" v-if="fileDisplay" />
        </div>
      </el-tab-pane >

      <el-tab-pane label="流转记录" name="record">
        <el-card class="box-card" shadow="never">
          <el-col :span="20" :offset="2">
            <div class="block">
              <el-timeline>
                <el-timeline-item v-for="(item,index) in historyProcNodeList" :key="index" :icon="setIcon(item.endTime)" :color="setColor(item.endTime)">
                  <p style="font-weight: 700">{{ item.activityName }}</p>
                  <el-card v-if="item.activityType === 'startEvent'" class="box-card" shadow="hover">
                    {{ item.assigneeName }} 在 {{ item.createTime }} 发起流程
                  </el-card>
                  <el-card v-if="item.activityType === 'userTask'" class="box-card" shadow="hover">
                    <el-descriptions :column="5" :labelStyle="{'font-weight': 'bold'}">
                      <el-descriptions-item label="实际办理">{{ item.assigneeName || '-'}}</el-descriptions-item>
                      <el-descriptions-item label="候选办理">{{ item.candidate || '-'}}</el-descriptions-item>
                      <el-descriptions-item label="接收时间">{{ item.createTime || '-'}}</el-descriptions-item>
                      <el-descriptions-item label="办结时间">{{ item.endTime || '-' }}</el-descriptions-item>
                      <el-descriptions-item label="耗时">{{ item.duration || '-'}}</el-descriptions-item>
                    </el-descriptions>
                    <div v-if="item.commentList && item.commentList.length > 0">
                      <div v-for="(comment, index) in item.commentList" :key="index">
                        <el-divider content-position="left">
                          <el-tag :type="approveTypeTag(comment.type)" size="mini">{{ commentType(comment.type) }}</el-tag>
                          <el-tag type="info" effect="plain" size="mini">{{ comment.time }}</el-tag>
                        </el-divider>
                        <span>{{ comment.fullMessage }}</span>
                      </div>
                    </div>
                  </el-card>
                  <el-card v-if="item.activityType === 'endEvent'" class="box-card" shadow="hover">
                    {{ item.createTime }} 结束流程
                  </el-card>
                </el-timeline-item>
              </el-timeline>
            </div>
          </el-col>
        </el-card>
      </el-tab-pane>

      <el-tab-pane label="流程跟踪" name="track">
        <el-card class="box-card" shadow="never">
          <process-viewer :key="`designer-${loadIndex}`" :style="'height:' + height" :xml="xmlData"
                          :finishedInfo="finishedInfo" :allCommentList="historyProcNodeList"
          />
        </el-card>
      </el-tab-pane>
    </el-tabs>

    <!--退回流程-->
    <el-dialog :title="returnTitle" :visible.sync="returnOpen" width="40%" append-to-body>
      <el-form ref="taskForm" :model="taskForm" label-width="80px" >
        <el-form-item label="退回节点" prop="targetKey">
          <el-radio-group v-model="taskForm.targetKey">
            <el-radio-button
              v-for="item in returnTaskList"
              :key="item.id"
              :label="item.id"
            >{{item.name}}</el-radio-button>
          </el-radio-group>
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button @click="returnOpen = false">取 消</el-button>
        <el-button type="primary" @click="submitReturn">确 定</el-button>
      </span>
    </el-dialog>

    <el-dialog :title="userData.title" :visible.sync="userData.open" width="60%" append-to-body>
      <el-row type="flex" :gutter="20">
        <!--部门数据-->
        <el-col :span="5">
          <el-card shadow="never" style="height: 100%">
            <div slot="header">
              <span>部门列表</span>
            </div>
            <div class="head-container">
              <el-input v-model="deptName" placeholder="请输入部门名称" clearable size="small" prefix-icon="el-icon-search"/>
              <el-tree
                :data="deptOptions"
                :props="deptProps"
                :expand-on-click-node="false"
                :filter-node-method="filterNode"
                ref="tree"
                default-expand-all
                @node-click="handleNodeClick"
              />
            </div>
          </el-card>
        </el-col>
        <el-col :span="18">
          <el-table ref="userTable"
                    :key="userData.type"
                    height="500"
                    v-loading="userLoading"
                    :data="userList"
                    highlight-current-row
                    @current-change="changeCurrentUser"
                    @selection-change="handleSelectionChange">
            <el-table-column v-if="userData.type === 'copy' || userData.type === 'next'" width="55" type="selection" />
            <el-table-column v-else width="30">
              <template slot-scope="scope">
                <el-radio :label="scope.row.userId" v-model="currentUserId">{{''}}</el-radio>
              </template>
            </el-table-column>
            <el-table-column label="用户名" align="center" prop="nickName" />
            <el-table-column label="手机" align="center" prop="phonenumber" />
            <el-table-column label="部门" align="center" prop="dept.deptName" />
          </el-table>
          <pagination
            :total="total"
            :page.sync="queryParams.pageNum"
            :limit.sync="queryParams.pageSize"
            @pagination="getList"
          />
        </el-col>
      </el-row>
      <span slot="footer" class="dialog-footer">
        <el-button @click="userData.open = false">取 消</el-button>
        <el-button type="primary" @click="submitUserData">确 定</el-button>
      </span>
    </el-dialog>
  </div>
</template>

<script>
import { detailProcess } from '@/api/workflow/process'
import Parser from '@/utils/generator/parser'
import { complete, delegate, transfer, rejectTask, returnList, returnTask } from '@/api/workflow/task'
import { selectUser, deptTreeSelect } from '@/api/system/user'
import ProcessViewer from '@/components/ProcessViewer'
import '@riophae/vue-treeselect/dist/vue-treeselect.css'
import Treeselect from '@riophae/vue-treeselect'
import formViewer from '@/components/formdesigner/components/formViewer'

export default {
  name: "WorkDetail",
  components: {
    ProcessViewer,
    Parser,
    Treeselect,
    formViewer
  },
  props: {},
  computed: {
    commentType() {
      return val => {
        switch (val) {
          case '1': return '通过'
          case '2': return '退回'
          case '3': return '驳回'
          case '4': return '委派'
          case '5': return '转办'
          case '6': return '终止'
          case '7': return '撤回'
        }
      }
    },
    approveTypeTag() {
      return val => {
        switch (val) {
          case '1': return 'success'
          case '2': return 'warning'
          case '3': return 'danger'
          case '4': return 'primary'
          case '5': return 'success'
          case '6': return 'danger'
          case '7': return 'info'
        }
      }
    }
  },
  data() {
    return {
      height: document.documentElement.clientHeight - 205 + 'px;',
      // 模型xml数据
      loadIndex: 0,
      xmlData: undefined,
      finishedInfo: {
        finishedSequenceFlowSet: [],
        finishedTaskSet: [],
        unfinishedTaskSet: [],
        rejectedTaskSet: []
      },
      historyProcNodeList: [],
      // 部门名称
      deptName: undefined,
      // 部门树选项
      deptOptions: undefined,
      userLoading: false,
      // 用户表格数据
      userList: null,
      deptProps: {
        children: "children",
        label: "label"
      },
      // 查询参数
      queryParams: {
        pageNum: 1,
        pageSize: 10,
        deptId: undefined
      },
      total: 0,
      // 遮罩层
      loading: true,
      taskForm:{
        comment:"", // 意见内容
        procInsId: "", // 流程实例编号
        taskId: "" ,// 流程任务编号
        copyUserIds: "", // 抄送人Id
        vars: "",
        targetKey:""
      },
      rules: {
        comment: [{ required: true, message: '请输入审批意见', trigger: 'blur' }],
      },
      currentUserId: null,
      variables: [], // 流程变量数据
      taskFormOpen: false,
      taskFormData: {}, // 流程变量数据
      processFormList: [], // 流程变量数据
      formOpen: false, // 是否加载流程变量数据
      returnTaskList: [],  // 回退列表数据
      processed: false,
      returnTitle: null,
      returnOpen: false,
      rejectOpen: false,
      rejectTitle: null,
      userData: {
        title: '',
        type: '',
        open: false,
      },
      copyUser: [],
      nextUser: [],
      userMultipleSelection: [],
      userDialogTitle: '',
      userOpen: false,
      formVal:[], //formdesigner关联值
      formViewData: [], //显示formdesigner的输入后提交的表单数据
      fileDisplay: false, // formdesigner是否显示上传的文件控件
      fileList: [], //表单设计器上传的文件列表
      activeName:'', //获取当然tabname
    };
  },
  created() {
    this.initData();
  },
  mounted() {

  },
  methods: {
    initData() {
      this.taskForm.procInsId = this.$route.params && this.$route.params.procInsId;
      this.taskForm.taskId  = this.$route.query && this.$route.query.taskId;
      this.processed = this.$route.query && eval(this.$route.query.processed || false);
      // 流程任务重获取变量表单
      this.getProcessDetails(this.taskForm.procInsId, this.taskForm.taskId);
      this.loadIndex = this.taskForm.procInsId;
      if(this.processed) {
        this.activeName = "approval";
      }
      else {
        this.activeName = "form";
        // 回填数据,这里主要是处理文件列表显示,临时解决,以后应该在formdesigner里完成
        this.processFormList.forEach((item, i) => {
          if (item.hasOwnProperty('list')) {
            this.fillFormData(item.list, item)
            // 更新表单
            this.key = +new Date().getTime()
          }
        });
      }
    },
    /** 查询部门下拉树结构 */
    getTreeSelect() {
      deptTreeSelect().then(response => {
        this.deptOptions = response.data;
      });
    },
    /** 查询用户列表 */
    getList() {
      this.userLoading = true;
      selectUser(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
        this.userList = response.rows;
        this.total = response.total;
        this.toggleSelection(this.userMultipleSelection);
        this.userLoading = false;
      });
    },
    // 筛选节点
    filterNode(value, data) {
      if (!value) return true;
      return data.label.indexOf(value) !== -1;
    },
    changeTab(tab, event) {
      console.log("changeTab tab=",tab);
      if(tab.name === 'form') {
        console.log("changeTab this.processFormList=",this.processFormList);
        // 回填数据,这里主要是处理文件列表显示,临时解决,以后应该在formdesigner里完成
        this.processFormList.forEach((item, i) => {
          if (item.hasOwnProperty('list')) {
            this.fillFormData(item.list, item)
            // 更新表单
            this.key = +new Date().getTime()
          }
        });

      }
    },
    fillFormData(list, formConf) { // for formdesigner
      console.log("fillFormData list=",list);
      console.log("fillFormData formConf=",formConf);
      list.forEach((item, i) => {
        // 特殊处理el-upload,包括 回显图片
        if(formConf.formValues[item.id] != '') {
          const val = formConf.formValues[item.id];
          if (item.ele === 'el-upload') {
            console.log('fillFormData val=',val)
            if(item['list-type'] != 'text') {//图片
              this.fileList = []    //隐藏加的el-upload文件列表
              //item['file-list'] = JSON.parse(val)
              if(val != '') {
                item['file-list'] = JSON.parse(val)
              }
            }
            else {  //列表
              console.log("列表fillFormData val",val)
              this.fileList = JSON.parse(val)
              item['file-list'] = [] //隐藏加的表单设计器的文件列表
            }
            // 回显图片
            this.fileDisplay = true
          }
        }

        if (Array.isArray(item.columns)) {
          this.fillFormData(item.columns, formConf)
        }
      })
    },
    //点击文件列表中已上传文件进行下载
    handleFilePreview(file) {
      location.href=file.url;
    },
    // 节点单击事件
    handleNodeClick(data) {
      this.queryParams.deptId = data.id;
      this.getList();
    },
    setIcon(val) {
      if (val) {
        return "el-icon-check";
      } else {
        return "el-icon-time";
      }
    },
    setColor(val) {
      if (val) {
        return "#2bc418";
      } else {
        return "#b3bdbb";
      }
    },
    // 多选框选中数据
    handleSelectionChange(selection) {
      this.userMultipleSelection = selection
    },
    toggleSelection(selection) {
      if (selection && selection.length > 0) {
        this.$nextTick(()=> {
          selection.forEach(item => {
            let row = this.userList.find(k => k.userId === item.userId);
            this.$refs.userTable.toggleRowSelection(row);
          })
        })
      } else {
        this.$nextTick(() => {
          this.$refs.userTable.clearSelection();
        });
      }
    },
    // 关闭标签
    handleClose(type, tag) {
      let userObj = this.userMultipleSelection.find(item => item.userId === tag.id);
      this.userMultipleSelection.splice(this.userMultipleSelection.indexOf(userObj), 1);
      if (type === 'copy') {
        this.copyUser = this.userMultipleSelection;
        // 设置抄送人ID
        if (this.copyUser && this.copyUser.length > 0) {
          const val = this.copyUser.map(item => item.id);
          this.taskForm.copyUserIds = val instanceof Array ? val.join(',') : val;
        } else {
          this.taskForm.copyUserIds = '';
        }
      } else if (type === 'next') {
        this.nextUser = this.userMultipleSelection;
        // 设置抄送人ID
        if (this.nextUser && this.nextUser.length > 0) {
          const val = this.nextUser.map(item => item.id);
          this.taskForm.nextUserIds = val instanceof Array ? val.join(',') : val;
        } else {
          this.taskForm.nextUserIds = '';
        }
      }
    },
    /** 流程变量赋值 */
    handleCheckChange(val) {
      if (val instanceof Array) {
        this.taskForm.values = {
          "approval": val.join(',')
        }
      } else {
        this.taskForm.values = {
          "approval": val
        }
      }
    },
    getProcessDetails(procInsId, taskId) {
      const params = {procInsId: procInsId, taskId: taskId}
      detailProcess(params).then(res => {
        console.log("detailProcess res=",res);
        const data = res.data;
        this.xmlData = data.bpmnXml;
        this.processFormList = data.processFormList;
        this.processFormList.forEach((item, index) => {
          this.formVal[index] = JSON.stringify(item.formValues);
          this.formViewData[index] = JSON.stringify(item);
        });
        this.taskFormOpen = data.existTaskForm;
        if (this.taskFormOpen) {
          this.taskFormData = data.taskFormData;
        }
        this.historyProcNodeList = data.historyProcNodeList;
        this.finishedInfo = data.flowViewer;
        this.formOpen = true
      })
    },
    onSelectCopyUsers() {
      this.userMultipleSelection = this.copyUser;
      this.onSelectUsers('添加抄送人', 'copy')
    },
    onSelectNextUsers() {
      this.userMultipleSelection = this.nextUser;
      this.onSelectUsers('指定审批人', 'next')
    },
    onSelectUsers(title, type) {
      this.userData.title = title;
      this.userData.type = type;
      this.getTreeSelect();
      this.getList()
      this.userData.open = true;
    },
    /** 通过任务 */
    handleComplete() {
      // 校验表单
      const taskFormRef = this.$refs.taskFormParser;
      const isExistTaskForm = taskFormRef !== undefined;
      // 若无任务表单,则 taskFormPromise 为 true,即不需要校验
      const taskFormPromise = !isExistTaskForm ? true : new Promise((resolve, reject) => {
        taskFormRef.$refs[taskFormRef.formConfCopy.formRef].validate(valid => {
          valid ? resolve() : reject()
        })
      });
      const approvalPromise = new Promise((resolve, reject) => {
        this.$refs['taskForm'].validate(valid => {
          valid ? resolve() : reject()
        })
      });
      Promise.all([taskFormPromise, approvalPromise]).then(() => {
        if (isExistTaskForm) {
          this.taskForm.variables = taskFormRef[taskFormRef.formConfCopy.formModel]
        }
        complete(this.taskForm).then(response => {
          this.$modal.msgSuccess(response.msg);
          this.goBack();
        });
      })
    },
    /** 委派任务 */
    handleDelegate() {
      this.$refs["taskForm"].validate(valid => {
        if (valid) {
          this.userData.type = 'delegate';
          this.userData.title = '委派任务'
          this.userData.open = true;
          this.getTreeSelect();
        }
      })
    },
    /** 转办任务 */
    handleTransfer(){
      this.$refs["taskForm"].validate(valid => {
        if (valid) {
          this.userData.type = 'transfer';
          this.userData.title = '转办任务';
          this.userData.open = true;
          this.getTreeSelect();
        }
      })
    },
    /** 拒绝任务 */
    handleReject() {
      this.$refs["taskForm"].validate(valid => {
        if (valid) {
          const _this = this;
          this.$modal.confirm('拒绝审批单流程会终止,是否继续?').then(function() {
            return rejectTask(_this.taskForm);
          }).then(res => {
            this.$modal.msgSuccess(res.msg);
            this.goBack();
          });
        }
      });
    },
    changeCurrentUser(val) {
      this.currentUserId = val.userId
    },
    /** 返回页面 */
    goBack() {
      // 关闭当前标签页并返回上个页面
      this.$tab.closePage(this.$route)
      this.$router.back()
    },
    /** 接收子组件传的值 */
    getData(data) {
      if (data) {
        const variables = [];
        data.fields.forEach(item => {
          let variableData = {};
          variableData.label = item.__config__.label
          // 表单值为多个选项时
          if (item.__config__.defaultValue instanceof Array) {
            const array = [];
            item.__config__.defaultValue.forEach(val => {
              array.push(val)
            })
            variableData.val = array;
          } else {
            variableData.val = item.__config__.defaultValue
          }
          variables.push(variableData)
        })
        this.variables = variables;
      }
    },
    submitUserData() {
      let type = this.userData.type;
      if (type === 'copy' || type === 'next') {
        if (!this.userMultipleSelection || this.userMultipleSelection.length <= 0) {
          this.$modal.msgError("请选择用户");
          return false;
        }
        let userIds = this.userMultipleSelection.map(k => k.userId);
        if (type === 'copy') {
          // 设置抄送人ID信息
          this.copyUser = this.userMultipleSelection;
          this.taskForm.copyUserIds = userIds instanceof Array ? userIds.join(',') : userIds;
        } else if (type === 'next') {
          // 设置下一级审批人ID信息
          this.nextUser = this.userMultipleSelection;
          this.taskForm.nextUserIds = userIds instanceof Array ? userIds.join(',') : userIds;
        }
        this.userData.open = false;
      } else {
        if (!this.taskForm.comment) {
          this.$modal.msgError("请输入审批意见");
          return false;
        }
        if (!this.currentUserId) {
          this.$modal.msgError("请选择用户");
          return false;
        }
        this.taskForm.userId = this.currentUserId;
        if (type === 'delegate') {
          delegate(this.taskForm).then(res => {
            this.$modal.msgSuccess(res.msg);
            this.goBack();
          });
        }
        if (type === 'transfer') {
          transfer(this.taskForm).then(res => {
            this.$modal.msgSuccess(res.msg);
            this.goBack();
          });
        }
      }

    },
    /** 可退回任务列表 */
    handleReturn() {
      this.$refs['taskForm'].validate(valid => {
        if (valid) {
          this.returnTitle = "退回流程";
          returnList(this.taskForm).then(res => {
            this.returnTaskList = res.data;
            this.taskForm.values = null;
            this.returnOpen = true;
          })
        }
      });

    },
    /** 提交退回任务 */
    submitReturn() {
      this.$refs["taskForm"].validate(valid => {
        if (valid) {
          if (!this.taskForm.targetKey) {
            this.$modal.msgError("请选择退回节点!");
          }
          returnTask(this.taskForm).then(res => {
            this.$modal.msgSuccess(res.msg);
            this.goBack()
          });
        }
      });
    }
  }
};
</script>
<style lang="scss" scoped>
.clearfix:before,
.clearfix:after {
  display: table;
  content: "";
}
.clearfix:after {
  clear: both
}

.box-card {
  width: 100%;
  margin-bottom: 20px;
}

.el-tag + .el-tag {
  margin-left: 10px;
}

.el-row {
  margin-bottom: 20px;
  &:last-child {
    margin-bottom: 0;
  }
}
.el-col {
  border-radius: 4px;
}

.button-new-tag {
  margin-left: 10px;
}
</style>

2、后端

单个上传文件修改如下:

    /**
     * 通用上传请求(单个)
     */
    @PostMapping("/upload")
    @ResponseBody
    public R<Map<String, String>> uploadFile(MultipartFile file) throws Exception
    {
        try
        {
        	 if(Constants.UPLOAD_TYPE_LOCAL.equals(uploadtype)) {
			     // 上传文件路径
			     String filePath = RuoYiConfig.getUploadPath();
			     // 上传并返回新文件名称
			     String fileName = FileUploadUtils.upload(filePath, file);
			     String url = serverConfig.getUrl() + fileName;
			     Map<String, String> map = new HashMap<>(4);
			     map.put("url", url);
			     map.put("fileName", fileName);
			     map.put("newFileName", FileUtils.getName(fileName));
			     map.put("originalFilename", file.getOriginalFilename());
			     return R.ok(map); 
        	 }
        	 else {
        		 SysOssVo oss = iSysOssService.upload(file);
    	         Map<String, String> map = new HashMap<>(3);
    	         map.put("url", oss.getUrl());
    	         map.put("fileName", oss.getOriginalName());
    	         map.put("ossId", oss.getOssId().toString());
    	         return R.ok(map); 
        	 }
           
        }
        catch (Exception e)
        {
            return R.fail(e.getMessage());
        }
    }

3、效果图

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1015542.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

IDEA中Debug测试的基本使用

Debug简介 Debug是用来追踪代码&#xff0c;通常在程序运行中出现异常的时候启动debug模式可以分析定位异常发生的位置&#xff0c;以及在运行过程中参数的变化&#xff0c;通常我们也可以启动Debug模式来跟踪代码的运行流程去学习三方框架的源码 Debug与Junit的区别 Debug与JU…

力扣236 补9.14

做不来&#xff0c;我做中等题基本上都是没有思路&#xff0c;这里需要先遍历祖先节点&#xff0c;那必然用先序遍历&#xff0c;这题还是官方题解容易理解&#xff0c;第二火的题解反而把我弄得脑袋昏昏的。 class Solution { TreeNode ans; public TreeNode lowestCommonAnce…

私域流量的优势

私域流量是指由自身品牌或个人拥有并具备完全掌控权的流量资源。它相比于传统的广告推广&#xff0c;拥有独特的优势。 首先&#xff0c;私域流量能够更加精准地定位目标用户&#xff0c;实现精准传播。不再盲目投放广告&#xff0c;而是通过建立自身社群、粉丝群&#xff0c;获…

Postman应用——下载注册和登录

文章目录 下载安装注册登录注册账号登录账号 下载安装 Postman下载&#xff1a;https://www.postman.com/ 访问链接后&#xff0c;进入首页&#xff0c;根据自己的操作系统下载对应的版本。 找到下载到的目录直接双击.exe文件&#xff0c;会默认安装在C盘&#xff0c;安装完会…

使用VMware 16 安装银河麒麟V10 --九五小庞

1.下载 银河麒麟系统V10 服务版镜像包&#xff1a; Kylin-Server-10-SP1-Release-Build04-20200711-x86_64.iso 百度云盘链接&#xff1a;https://pan.baidu.com/s/1z0GCEadvefUA8R988qDP5Q 提取码&#xff1a;1l0g 2.运行VMware Workstation&#xff0c;创建新的虚拟机&…

【动态规划刷题 15】最长定差子序列 最长的斐波那契子序列的长度

1218. 最长定差子序列 链接: 1218. 最长定差子序列 给你一个整数数组 arr 和一个整数 difference&#xff0c;请你找出并返回 arr 中最长等差子序列的长度&#xff0c;该子序列中相邻元素之间的差等于 difference 。 子序列 是指在不改变其余元素顺序的情况下&#xff0c;通…

python程序商业化,代码安全最终方案,pyinstaller与cython打包python执行程序

其实一般的程序安全上只需要两步就行&#xff0c;没必要再加密改解释器等&#xff0c;已经不可能反编译到原有python了&#xff0c;因为动态链接库就是汇编了&#xff0c;中间经历了python转c,c在转动态库&#xff0c;代码已经没有可读性了。但是一些密码等重要字符还是要处理好…

构建无限画布,协作数字绘图 | 开源日报 0915

tldraw/tldraw Stars: 16.4k License: Apache-2.0 tldraw 是一个协作数字白板项目&#xff0c;可在 tldraw.com 上使用。它的编辑器、用户界面和其他底层库都是开源的&#xff0c;并且可以通过 npm 进行分发。您可以使用 tldraw 为产品创建一个即插即用的白板&#xff0c;或者…

Smart Community(1)之设计规范

通过前面大数据开发相关知识的学习&#xff0c;准备做一个项目进行练习---我给他起了一个响亮的名字&#xff1a;基于HadoopHA的智慧社区服务平台 设计规范&#xff1a; 做一个项目之前肯定要先规定一些开发过程中的设计规范 &#xff08;一&#xff09;数据埋点规范&#xf…

Python中异常处理4-4

在Python中的异常处理4-1_棉猴的博客-CSDN博客中提到&#xff0c;在try块中的代码运行时如果出现异常&#xff0c;会自动抛出这个异常。可以通过raise语句手动抛出异常。 1 raise语句手动抛出异常 raise后面跟要抛出的异常类或者异常类的实例&#xff0c;表示手动抛出该异常&…

位图+布隆过滤器+海量数据并查集(它们都是哈希的应用)

一)位图: 首先计算一下存储一下10亿个整形数据&#xff0c;需要多大内存呢&#xff0c;多少个G呢&#xff1f; 2^3010亿&#xff0c;10亿个字节 byte kb mb gb 100000000个字节/1024/1024/10241G 所以10亿个字节就是1G&#xff0c;所以40亿个字节就是4G&#xff0c;也就是10个整…

电脑重装系统之后设置

edge一直处于正在同步设置关闭系统自动更新更改默认安装路径 edge一直处于正在同步设置 解决办法&#xff1a;卸载重新安装 用电脑管家16可以卸载 电脑管家16 链接&#xff1a;https://pan.baidu.com/s/1f5T4uXrumL8Fne9hyvTHcg?pwd0122 提取码&#xff1a;0122 edge 链接&am…

Go Moonbeam:Ai智能写作助手

【产品介绍】 • 名称 Go Moonbeam • 具体描述 Moonbeam是一个人工智能驱动的长篇写作助手。你可以用它创建散文&#xff0c;故事&#xff0c;文章&#xff0c;博客&#xff0c;和其他长形式的内容&#xff0c;可以轻松的将混乱的笔记转换为大纲。同时它…

对象创建和内存分配

对象创建和内存分配 Java中类创建是在平常不过的操作了&#xff0c;但是一个类的创建到底经历 了哪些过程呢&#xff1f; 对象创建 创建方法 使用关键字new一个对象 使用反射机制 User user (User)Class.forName("xxx.xxx.User").newInstance(); User user Us…

Linux开发工具之编译器gcc/g++

gcc/g是编译代码的&#xff0c;gcc/g都可以编译c语言的代码&#xff0c;但是c的代码只能用g来编译 在linux中&#xff0c;只要我们对源文件用gcc/g进行编译&#xff0c;就会生成一个可执行程序a.out&#xff0c;然后我们执行该程序就可得到结果了&#xff0c;下面来细看一下gcc…

深入了解==和equals的区别

1. 浅说和equals的区别 &#xff08;1&#xff09;比较的类型 不一样 可以比较基础数据类型和引用类型&#xff0c;比较基础数据类型的数据时比较的是值&#xff0c;比较引用对象时比较的是引用的地址。 equals比较引用类型&#xff0c;默认比较的是两个引用对象的引用地址&a…

Acwing 3302. 表达式求值

Acwing 3302. 表达式求值 题目描述思路讲解代码展示 题目描述 思路讲解 代码展示 #include <iostream> #include <cstring> #include <algorithm> #include <stack> #include <unordered_map>using namespace std;stack<int> num; stack…

redis链接阻塞,导致程序没有响应

目录 一、场景二、原因三、排查1、使用 info client 命令查看redis链接统计情况2、使用 client list 命令查看redis链接信息3、关闭程序&#xff0c;看阻塞的链接是否有所减少4、排查使用 blpop 命令的相关代码 四、解决 一、场景 1、程序在运行一段时间后&#xff0c;会出现没…

【分布式】分布式ID

目录 前言一、雪花算法snowflake1. 组成2. 优缺点3. 时钟回拨怎么解决a. 时钟回拨b. 解决方案 4. 项目中如何使用 二、基于Redis三、基于Zookeeper四、号段模式五、指定步长的自增ID六、UUID参考 六、扩展总结 前言 分布式场景下&#xff0c;一张表可能分散到多个数据结点上。因…

【数据结构】C++实现二叉搜索树

二叉搜索树的概念 二叉搜索树又称为二叉排序树&#xff0c;它或者是一棵空树&#xff0c;或者是具有以下性质的二叉树&#xff1a; 若它的左子树不为空&#xff0c;则左子树上所有结点的值都小于根结点的值。若它的右子树不为空&#xff0c;则右子树上所有结点的值都大于根结…