上传 多选文件,有部分文件会丢失

<template>
  <div class="upload-file">
    <!-- multiple  多选文件,有部分文件会丢失 -->
    <el-upload
      v-show="isDel"
      :action="uploadFileUrl"
      :before-upload="handleBeforeUpload"
      :file-list="modelValue"
      :limit="limit"
      :on-error="handleUploadError"
      :on-exceed="handleExceed"
      :on-success="handleUploadSuccess"
      :show-file-list="false"
      :headers="headers"
      class="upload-file-uploader"
      ref="upload"
      :disabled="props.modelValue.length >= props.limit ? true : false"
    >
      <!-- 上传按钮 -->
      <el-button
        class="shangchuanBtn"
        round
        :disabled="props.modelValue.length >= props.limit ? true : false"
        >上传图片</el-button
      >
      <!-- 上传提示 -->
      <template #tip>
        <div class="el-upload__tip" v-if="showTip">
          <template v-if="fileType">
            支持
            <b style="color: #f56c6c">{{ fileType.join("/") }}</b
            >格式
          </template>
          <template v-if="fileSize">
            , 大小
            <b style="color: #f56c6c">{{ fileSize }}MB</b>以内
          </template>
          <span>
            ,数量不超过
            <b style="color: #f56c6c">{{ limit }}</b
            >个
          </span>
        </div>
      </template>
    </el-upload>

    <div class="wrapperImg">
      <template v-for="(item, index) in modelValue">
        <div :key="item.url" v-if="item.url" class="upload-img">
          <el-image
            style="width: 150px; height: 150px"
            :src="baseUrl + item.url"
            fit="cover"
          />
          <div class="upload-btn">
            <div class="btn chakan" @click.prevent="handleChakan(item)"></div>
            <div class="btn xiazai" @click.prevent="handleDownload(item)"></div>
            <div
              v-if="!isRead"
              class="btn shanchu"
              @click.prevent="handleDelete(index)"
            ></div>
          </div>
        </div>
      </template>
    </div>

    <el-drawer
      :title="pdfTitle"
      v-model="openPdf"
      size="50%"
      custom-class="lookPage"
    >
      <div class="paddingBox">
        <img :src="currentFileUrl" />
      </div>
    </el-drawer>
  </div>
</template>

<script setup>
import { getToken } from "@/utils/auth";
const props = defineProps({
  modelValue: {
    type: Array,
    default: [],
  },
  // 数量限制
  limit: {
    type: Number,
    default: 5,
  },
  // 大小限制(MB)
  fileSize: {
    type: Number,
    default: 5,
  },
  // 文件类型, 例如['png', 'jpg', 'jpeg']
  fileType: {
    type: Array,
    default: () => [
      "doc",
      "docx",
      "xls",
      "ppt",
      "txt",
      "pdf",
      "png",
      "mp4",
      "mp3",
    ],
  },
  // 是否显示提示
  isShowTip: {
    type: Boolean,
    default: true,
  },
  //  查看pdf弹框内容
  pdfTitle: {
    type: String,
    default: "预览",
  },
  //  是否可删除
  isDel: {
    type: Boolean,
    default: true,
  },
  isRead: {
    type: Boolean,
    default: false,
  },
});

const { proxy } = getCurrentInstance();
const emit = defineEmits();
const number = ref(0);
const uploadList = ref([]);
const baseUrl = import.meta.env.VITE_APP_BASE_API;
const uploadFileUrl = ref(
  import.meta.env.VITE_APP_BASE_API + "/common/uploadtopdf"
); // 上传的图片服务器地址
const headers = ref({ Authorization: "Bearer " + getToken() });
const showTip = computed(
  () => props.isShowTip && (props.fileType || props.fileSize)
);
const openPdf = ref(false);
const currentFileUrl = ref("");

const currentFileType = ref("");

//判断是否显示“预览”按钮
const getPreviewAuth = computed(() => {
  return (row) => {
    let fileUrl = row.response ? row.response.url : row.url ? row.url : "";
    const fileType = getFileType(fileUrl)?.toLowerCase();
    const isPreview = ["jpg", "jpeg", "png", "pdf", "bpm", "avi", "mp4", "mp3"];
    return isPreview.indexOf(fileType) !== -1;
  };
});

//获取文件格式
function getFileType(fileUrl) {
  const fileType = fileUrl.split(".")[1];
  return fileType;
}

// 上传前校检格式和大小
function handleBeforeUpload(file) {
  // 校检文件类型

  if (props.fileType.length) {
    let fileExtension = "";
    if (file.name.lastIndexOf(".") > -1) {
      fileExtension = file.name
        .slice(file.name.lastIndexOf(".") + 1)
        .toLowerCase();
    }
    const isTypeOk = props.fileType.some((type) => {
      // if (file.type.indexOf(type) > -1) return true;
      if (fileExtension && fileExtension.indexOf(type) > -1) return true;
      return false;
    });
    if (!isTypeOk) {
      proxy.$modal.msgError(
        `文件格式不正确, 请上传${props.fileType.join("/")}格式文件!`
      );
      return false;
    }
  }
  console.log(props.modelValue);
  if (props.modelValue.length >= props.limit) {
    proxy.$modal.msgError(`上传文件数量不能超过 ${props.limit} 个!`);
    return false;
  }
  // 校检文件大小
  if (props.fileSize) {
    const isLt = file.size / 1024 / 1024 < props.fileSize;
    if (!isLt) {
      proxy.$modal.msgError(`上传文件大小不能超过 ${props.fileSize} MB!`);
      return false;
    }
  }
  proxy.$modal.loading("正在上传文件,请稍候...");
  return true;
}

// 文件个数超出
function handleExceed(files, fileList) {
  proxy.$modal.msgError(`上传文件数量不能超过 ${props.limit} 个!`);
}

// 上传失败
function handleUploadError(err) {
  proxy.$modal.msgError("上传文件失败");
}

// 上传成功回调
function handleUploadSuccess(res, file, fileList) {
  let oldImg = props.modelValue;
  let newVal = fileList.map((item) => {
    return {
      url: item.url || item?.response?.url,
      name: item.name || "图片",
    };
  });
  let newImgArr = oldImg.concat(newVal[newVal.length - 1]);
  emit("update:modelValue", newImgArr);
  proxy.$modal.closeLoading();
}

//换算文件大小(原文件单位:B,转成KB或MB)
function computeSize(size) {
  if (size) {
    return size / 1024 / 1024 > 1
      ? (size / 1024 / 1024).toFixed(2) + "MB"
      : parseInt(size / 1024) + "KB";
  } else {
    return "";
  }
}

// 删除文件
function handleDelete(index) {
  //清除el-upload内部的fileList
  proxy.$refs.upload.clearFiles();
  // proxy.$refs.upload.handleRemove(row);
  props.modelValue.splice(index, 1);
  emit("update:modelValue", props.modelValue);
}

//预览文件
function handleChakan(row) {
  currentFileUrl.value = import.meta.env.VITE_APP_BASE_API + row.url;
  openPdf.value = true;
}

//下载文件
function handleDownload(row) {
  console.log(row);
  let fileUrl = row.url;
  //&delete=true 下载后删除
  window.location.href =
    import.meta.env.VITE_APP_BASE_API +
    "/common/download4Url?fileUrl=" +
    fileUrl +
    "&fileName=" +
    row.name;
}
function leave() {
  openPdf.value = false;
}
// 获取文件名称
function getFileName(name) {
  if (name.lastIndexOf("/") > -1) {
    return name.slice(name.lastIndexOf("/") + 1);
  } else {
    return "";
  }
}

// 对象转成指定字符串分隔
function listToString(list, separator) {
  let strs = "";
  separator = separator || ",";
  for (let i in list) {
    strs += list[i].url + separator;
  }
  return strs != "" ? strs.substr(0, strs.length - 1) : "";
}
</script>

<style scoped lang="scss">
iframe {
  border: none !important;
}
img {
  max-width: 100%;
}
:deep(div) {
  .el-upload {
    text-align: left !important;
  }
  .el-upload {
    text-align: left !important;
  }
  .el-upload__tip {
    display: inline-block;
    float: none;
  }
  .el-upload__tip {
    display: inline-block;
    padding-left: 10px;
    float: none;
    cursor: auto;
  }
  .upload-file-uploader .el-upload--text {
    text-align: left !important;
  }
  .upload-file-uploader {
    margin-bottom: 5px;
  }
  .upload-file-list .el-upload-list__item {
    border: 1px solid #e4e7ed;
    line-height: 2;
    margin-bottom: 10px;
    position: relative;
  }
  .upload-file-list .ele-upload-list__item-content {
    display: flex;
    justify-content: space-between;
    align-items: center;
    color: inherit;
  }
  .ele-upload-list__item-content-action .el-link {
    margin-right: 10px;
  }
}
.wrapperImg {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  width: 870px;
  .upload-img {
    position: relative;
    width: 150px;
    height: 150px;
    margin: 10px;
    border-radius: 4px;
    overflow: hidden;

    .upload-btn {
      display: none;
      cursor: pointer;
      > div {
        margin-right: 14px;
        &:last-child {
          margin-right: 0;
        }
      }
    }
    &:hover {
      .upload-btn {
        width: 150px;
        height: 150px;
        position: absolute;
        top: 0;
        left: 0;
        background: rgba(0, 0, 0, 0.6);
        display: flex;
        align-items: center;
        justify-content: center;
      }
    }
  }
}
</style>

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
功能简介:1、admin文件夹下更新了admin_index.asp文件,在系统后台首页的“用户等级及设置”中增加了“用户批量删除”项,通过选择查询条件,可进行自动批量删除。2、admin文件夹下新增admin_user_delete1.asp文件,是用来执行删除的文件。3、此批量删除,同时把此用户相关的数据库信息、静态页文件上传附件一并删除,请谨慎使用。4、此插件设置了简单的防超时功能,但是独立服务器用户最好还是自己设置下IIS的超时时间(商业版用户请同时设置下SQL数据库的超时时间),尽可能的设置的大一些。如出现超时或者错误,可继续删除,一般无影响。5、此插件可用来清理以前恶意注册的用户。 安装说明: 1、备份当前博客站点下admin文件夹中的admin_index.asp文件。 2、附件下载后解压,得到admin文件夹,直接覆盖到博客站根目录即可。或者将解压包里的admin_index.asp文件及admin_user_delete1.asp文件覆盖到博客站点下的admin文件夹中即可。 使用方法: 1、请确定静态页目录(如user1、u文件夹)、uploadfiles文件夹(上传附件存放文件夹)、data文件夹(体验版数据库存放文件夹)有删除权限。 2、此插件分两部分:快速删除、自定义删除。两个栏目相互间无关联,都是独立的。 3、同栏目下的条件是可多选的。以自定义删除为例,可设定最后登录IP的同时,设定登陆次数。假设要删除IP为127.0.0.1的且登陆次数小于1的,则可在“最后登录ip”中输入“127.0.0.1”,且在“登录次数小于”中输入“1”,执行删除即可。 4、集成了删除文章内容包含关键字的用户的功能,设置了需要删除的关键字后,可删除包含此关键字的日志的发布者的全部信息。 注意事项: 1、批量删除是不可逆的,删除前必须备份好数据库。删除数据中出现的任何数据丢失问题,我方不负任何责任。 2、用户名搜索为模糊搜索,所以在输入查询条件的时候请尽量设置的长一些。 3、删除完毕后,请还原回原来的admin_index.asp文件,并把admin_user_delete1.asp文件删除。 4、此插件不适用于做过整合的站点。
迅睿CMS免费开源系统是基于PHP8语言采用最新CodeIgniter4作为开发框架生产的网站内容管理框架,提供“电脑网站 + 手机网站 + APP 接口”一体化网站技术解决方案。她拥有强大稳定底层框架,以灵活扩展为主的开发理念,二次开发方便且不破坏程序内核,为 WEB 艺术家创造的 PHP 建站程序,堪称 PHP 万能建站框架。 迅睿CMS免费开源系统特点: 一、程序架构 迅睿CMS框架是采用PHP8全新语法开发的web内容管理系统开发框架,拥有迅睿CMS强大的内容管理功能和灵活扩展的特性,堪称 PHP 万能建站框架。强大而灵活的内容模块和插件机制,开发者可以自定义内容模块,也可以根据自身的需求以插件的形式进行扩展。 迅睿CMS框架采用最新CodeIgniter4框架,拥有完善的二次开发文档,并且遵循框架原生编程风格,非常方便二次开发;CodeIgniter 安装包中包含《用户手册》,手册囊括了入门介绍、教程、“手把手”指导,还包括了框架组件的参考文档。 二、效率与安全 1、运用全新PHP8语法特性,设计时考虑到性能优化,运行效率高达4倍于PHP5系列开发环境 2、运用CI框架的扩展性和路由模式,加上ZF框架强大丰富的中间件和扩展包,大大提高系统的扩展性能 3、Zend框架官方全部扩展包支持自由引入本系统,按需加载模式,最大限度地提高开发效率 4、利用ZF提供的与安全相关的组件,包括 SQL 注入、XSS、CSRF、垃圾邮件和密码暴力破解攻击 5、动态缓存技术让动态页面新增支持缓存,让采用动态页面模式的网站访问速度更快,效率更高 6、全站支持HTTPS传输协议,更安全,支持小程序数据请求的URL规范 7、表单增加“csrf_token”验证功能,防护更强 三、多插件机制 框架采用多个Module作为App应用,迅睿CMS继续沿用此设计模式,并且支持多个App插件化。 1、插件目录结构:dayrui/App/***/。 2、插件支持独立运行。 3、插件内部结构遵循CI4App规则。 四、自定义CI扩展类 迅睿CMS在不破坏CI4框架本身的情况下,进行了扩展CI自带的类库。 1、重写CI错误异常显示类,中国化。 2、重写路由类,符合国内建站程序的URL结构,如:c=控制器&m=方法名&id=参数。 3、重写钩子类,CI4钩子类加载所有App中的自定义钩子,App数量过多时影响速度,迅睿CMS提出全局钩子配置文件。 4、重写安全类,强化过滤非法字符串。 五、模板解析类(视图) CI4本身的模板解析类不太灵活,迅睿CMS采用天睿自主研发天睿模板引擎技术,MVC设计模式实现业务逻辑与表现层的适当分离,使网页设计师能够轻松设计出理想的模板。 1、支持原生态PHP语法特性。 2、支持CI框架语法结构。 3、{变量}自定义系统标签语法结构。 4、模板缓存,只需要一次解析,提升性能。 六、自定义扩展类目录 迅睿CMS有全局Library目录,专门用于扩展类库,与Librarys用法不太一样,但原理一样。 1、全局Library调用。 2、可继承全局Library函数类。 3、App有自己独立的Library函数类。 4、跨App支持调用任意App的Library函数类。 七、网站模板机制 CI4不具备终端识别模式,迅睿CMS增加多终端识别和自定义终端显示。 1、迅睿CMS模板分为手机端和电脑端。 2、后台可以直接编辑网站模板和手机模板。 3、编辑模板自动备份,以免老模板丢失。 4、编辑模板时自动检测模板语法是否正确。 5、为模板文件中文命名,以免快速区分。 八、万能Table类 迅睿CMS框架为开发者准备了万能的Table类,此类用于对数据表的增删改查操作,只需要配置文件,逻辑功能由迅睿CMS来帮你完成。 1、支持任意表数据展示。 2、多表联合查询。 3、自定义字段格式入库规则。 九、自定义字段 迅睿CMS采用非常成熟的自定义字段方案,可以支持到栏目表自定义字段、内容表自定义字段、表单表自定义字段、用户表自定义字段、评论表自定义字段、页面表自定义字段、链接表自定义字段、tag表自定义字段等。 1、文本字段,有单行文本、多行文本、文本事件字段 2、上传字段,有单文件上传、多文件上传 3、日期时间字段,支持自定义年月格式显示 4、联动菜单字段,用于无限分类层级显示的数据,例如城市 5、百度地图字段,用于定位地图坐标,坐标范围内筛选数据 6、富文本字段,百度编辑器、百度移动编辑器 7、选项字段,单选字段、多选字段、下拉选择字段 8、颜色字段,用于选择网页颜色值 9、属性字段,用于类似于商品属性的数据 10、内容关联字段,用于加载其他模块内容的字段,例如专题功能 11、价格字段,用于CMF站内购物交易,例如文章买卖、下载收费 12

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值